107 lines
3.2 KiB
JavaScript
107 lines
3.2 KiB
JavaScript
const draftRingSector = (part, rot, an, radIn, radEx, rotate = false) => {
|
|
let { utils, Point, points, Path } = part.shorthand()
|
|
|
|
const roundExtended = (radius, angle = 90) => {
|
|
let arg = utils.deg2rad(angle / 2)
|
|
|
|
return (radius * 4 * (1 - Math.cos(arg))) / Math.sin(arg) / 3
|
|
}
|
|
|
|
/**
|
|
* Calculates the distance of the control point for the internal
|
|
* and external arcs using bezierCircleExtended
|
|
*/
|
|
let distIn = roundExtended(radIn, an / 2)
|
|
let distEx = roundExtended(radEx, an / 2)
|
|
// The centre of the circles
|
|
points.center = new Point(0, 0)
|
|
|
|
/**
|
|
* This function is expected to draft ring sectors for
|
|
* angles up to 180%. Since roundExtended works
|
|
* best for angles until 90º, we generate the ring
|
|
* sector using the half angle and then duplicate it
|
|
*/
|
|
|
|
/**
|
|
* The first point of the internal arc, situated at
|
|
* a radIn distance below the centre
|
|
*/
|
|
points.in1 = points.center.shift(-90, radIn)
|
|
|
|
/**
|
|
* The control point for 'in1'. It's situated at a
|
|
* distance $distIn calculated with bezierCircleExtended
|
|
* and the line between it and 'in1' is perpendicular to
|
|
* the line between 'in1' and the centre, so it's
|
|
* shifted in the direction 0º
|
|
*/
|
|
points.in1C = points.in1.shift(0, distIn)
|
|
|
|
/**
|
|
* The second point of the internal arc, situated at
|
|
* a $radIn distance of the centre in the direction
|
|
* $an/2 - 90º
|
|
*/
|
|
points.in2 = points.center.shift(an / 2 - 90, radIn)
|
|
|
|
/**
|
|
* The control point for 'in2'. It's situated at a
|
|
* distance $distIn calculated with bezierCircleExtended
|
|
* and the line between it and 'in2' is perpendicular to
|
|
* the line between 'in2' and the centre, so it's
|
|
* shifted in the direction $an/2 + 180º
|
|
*/
|
|
points.in2C = points.in2.shift(an / 2 + 180, distIn)
|
|
|
|
/**
|
|
* The points for the external arc are generated in the
|
|
* same way, using $radEx and $distEx instead
|
|
*/
|
|
points.ex1 = points.center.shift(-90, radEx)
|
|
points.ex1C = points.ex1.shift(0, distEx)
|
|
points.ex2 = points.center.shift(an / 2 - 90, radEx)
|
|
points.ex2C = points.ex2.shift(an / 2 + 180, distEx)
|
|
|
|
// Flip all the points to generate the full ring sector
|
|
for (let id of ['in2', 'in2C', 'in1C', 'ex1C', 'ex2C', 'ex2'])
|
|
points[id + 'Flipped'] = points[id].flipX()
|
|
|
|
// Rotate all the points an angle rot
|
|
for (let id of [
|
|
'in1',
|
|
'in1C',
|
|
'in2',
|
|
'in2C',
|
|
'ex1',
|
|
'ex1C',
|
|
'ex2',
|
|
'ex2C',
|
|
'in2Flipped',
|
|
'in2CFlipped',
|
|
'in1CFlipped',
|
|
'ex1CFlipped',
|
|
'ex2CFlipped',
|
|
'ex2Flipped'
|
|
])
|
|
points[id + 'Rotated'] = points[id].rotate(rot, points.center)
|
|
|
|
if (rotate) {
|
|
// Rotate all points so the line from in1Rotated to ex1Rotated is vertical
|
|
let deg = 270 - points.in2Flipped.angle(points.ex2Flipped)
|
|
for (let id in points) {
|
|
points[id] = points[id].rotate(deg, points.in2Flipped)
|
|
}
|
|
}
|
|
// Return the path of the full ring sector
|
|
return new Path()
|
|
.move(points.in2Flipped)
|
|
.curve(points.in2CFlipped, points.in1CFlipped, points.in1)
|
|
.curve(points.in1C, points.in2C, points.in2)
|
|
.line(points.ex2)
|
|
.curve(points.ex2C, points.ex1C, points.ex1)
|
|
.curve(points.ex1CFlipped, points.ex2CFlipped, points.ex2Flipped)
|
|
.close()
|
|
}
|
|
|
|
export default draftRingSector
|