2019-08-03 15:03:33 +02:00
|
|
|
import Path from './path'
|
|
|
|
import Point from './point'
|
2020-11-04 20:06:19 +01:00
|
|
|
import { Bezier } from 'bezier-js'
|
2018-12-09 14:17:46 +01:00
|
|
|
|
2018-12-16 18:06:01 +01:00
|
|
|
export function capitalize(string) {
|
2019-08-03 15:03:33 +02:00
|
|
|
return string.charAt(0).toUpperCase() + string.slice(1)
|
2018-12-16 18:06:01 +01:00
|
|
|
}
|
|
|
|
|
2020-07-18 16:48:29 +02:00
|
|
|
/** Checks for a valid coordinate value **/
|
|
|
|
export function isCoord(value) {
|
|
|
|
return value === value // NaN does not equal itself
|
|
|
|
? typeof value === 'number'
|
|
|
|
: false
|
|
|
|
}
|
|
|
|
|
2018-07-23 11:12:06 +00:00
|
|
|
/** Returns internal hook name for a macro */
|
2018-07-23 11:44:34 +00:00
|
|
|
export function macroName(name) {
|
2019-08-03 15:03:33 +02:00
|
|
|
return `_macro_${name}`
|
2018-07-12 12:53:49 +00:00
|
|
|
}
|
|
|
|
|
2018-07-14 16:04:39 +00:00
|
|
|
/** Find intersection of two (endless) lines */
|
2018-08-23 15:57:23 +02:00
|
|
|
export function beamsIntersect(a1, a2, b1, b2) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let slopeA = a1.slope(a2)
|
|
|
|
let slopeB = b1.slope(b2)
|
|
|
|
if (slopeA === slopeB) return false // Parallel lines
|
2018-07-14 16:04:39 +00:00
|
|
|
|
2021-07-14 18:01:04 +02:00
|
|
|
// Check for vertical line A
|
2021-08-30 11:40:16 +02:00
|
|
|
if (Math.round(a1.x * 10000) === Math.round(a2.x * 10000))
|
2021-07-14 18:01:04 +02:00
|
|
|
return new Point(a1.x, slopeB * a1.x + (b1.y - slopeB * b1.x))
|
|
|
|
// Check for vertical line B
|
2021-08-30 11:40:16 +02:00
|
|
|
else if (Math.round(b1.x * 10000) === Math.round(b2.x * 10000))
|
2021-07-14 18:01:04 +02:00
|
|
|
return new Point(b1.x, slopeA * b1.x + (a1.y - slopeA * a1.x))
|
2018-07-14 16:04:39 +00:00
|
|
|
else {
|
|
|
|
// Swap points if line A or B goes from right to left
|
2019-08-03 15:03:33 +02:00
|
|
|
if (a1.x > a2.x) a1 = a2.copy()
|
|
|
|
if (b1.x > b2.x) b1 = b2.copy()
|
2018-07-14 16:04:39 +00:00
|
|
|
// Find y intercept
|
2019-08-03 15:03:33 +02:00
|
|
|
let iA = a1.y - slopeA * a1.x
|
|
|
|
let iB = b1.y - slopeB * b1.x
|
2018-07-14 16:04:39 +00:00
|
|
|
|
|
|
|
// Find intersection
|
2019-08-03 15:03:33 +02:00
|
|
|
let x = (iB - iA) / (slopeA - slopeB)
|
|
|
|
let y = slopeA * x + iA
|
2018-07-14 16:04:39 +00:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
return new Point(x, y)
|
2018-07-14 16:04:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Find intersection of two line segments */
|
2018-08-23 15:57:23 +02:00
|
|
|
export function linesIntersect(a1, a2, b1, b2) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let p = beamsIntersect(a1, a2, b1, b2)
|
|
|
|
if (!p) return false
|
|
|
|
let lenA = a1.dist(a2)
|
|
|
|
let lenB = b1.dist(b2)
|
|
|
|
let lenC = a1.dist(p) + p.dist(a2)
|
|
|
|
let lenD = b1.dist(p) + p.dist(b2)
|
|
|
|
if (Math.round(lenA) == Math.round(lenC) && Math.round(lenB) == Math.round(lenD)) return p
|
|
|
|
else return false
|
2018-07-14 16:04:39 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 15:55:15 +02:00
|
|
|
/** Finds out whether a point lies on an endless line */
|
2018-08-23 15:57:23 +02:00
|
|
|
export function pointOnBeam(from, to, check, precision = 1e6) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (from.sitsOn(check)) return true
|
|
|
|
if (to.sitsOn(check)) return true
|
|
|
|
let cross = check.dx(from) * to.dy(from) - check.dy(from) * to.dx(from)
|
2018-08-23 15:57:23 +02:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
if (Math.abs(Math.round(cross * precision) / precision) === 0) return true
|
|
|
|
else return false
|
2018-08-22 15:55:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Finds out whether a point lies on a line segment */
|
2018-08-23 15:57:23 +02:00
|
|
|
export function pointOnLine(from, to, check, precision = 1e6) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (!pointOnBeam(from, to, check, precision)) return false
|
|
|
|
let lenA = from.dist(to)
|
|
|
|
let lenB = from.dist(check) + check.dist(to)
|
|
|
|
if (Math.round(lenA) == Math.round(lenB)) return true
|
|
|
|
else return false
|
2018-08-22 15:55:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Finds out whether a point lies on a curve */
|
|
|
|
export function pointOnCurve(start, cp1, cp2, end, check) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (start.sitsOn(check)) return true
|
|
|
|
if (end.sitsOn(check)) return true
|
2018-08-22 15:55:15 +02:00
|
|
|
let curve = new Bezier(
|
|
|
|
{ x: start.x, y: start.y },
|
|
|
|
{ x: cp1.x, y: cp1.y },
|
|
|
|
{ x: cp2.x, y: cp2.y },
|
|
|
|
{ x: end.x, y: end.y }
|
2019-08-03 15:03:33 +02:00
|
|
|
)
|
2018-08-22 15:55:15 +02:00
|
|
|
let intersections = curve.intersects({
|
|
|
|
p1: { x: check.x - 1, y: check.y },
|
2021-04-24 10:16:31 +02:00
|
|
|
p2: { x: check.x + 1, y: check.y },
|
2019-08-03 15:03:33 +02:00
|
|
|
})
|
2020-08-09 09:50:49 +02:00
|
|
|
if (intersections.length === 0) {
|
|
|
|
// Handle edge case of a curve that's a perfect horizontal line
|
|
|
|
intersections = curve.intersects({
|
|
|
|
p1: { x: check.x, y: check.y - 1 },
|
2021-04-24 10:16:31 +02:00
|
|
|
p2: { x: check.x, y: check.y + 1 },
|
2020-08-09 09:50:49 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
if (intersections.length > 0) return intersections.shift()
|
|
|
|
else return false
|
2018-08-22 15:55:15 +02:00
|
|
|
}
|
|
|
|
|
2019-02-17 21:40:26 +01:00
|
|
|
/** Splits a curve on a point */
|
|
|
|
export function splitCurve(start, cp1, cp2, end, split) {
|
2020-04-18 11:38:08 +02:00
|
|
|
let [c1, c2] = new Path().move(start).curve(cp1, cp2, end).split(split)
|
2019-02-17 21:40:26 +01:00
|
|
|
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
start: c1.ops[0].to,
|
|
|
|
cp1: c1.ops[1].cp1,
|
|
|
|
cp2: c1.ops[1].cp2,
|
2021-04-24 10:16:31 +02:00
|
|
|
end: c1.ops[1].to,
|
2019-02-17 21:40:26 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
start: c2.ops[0].to,
|
|
|
|
cp1: c2.ops[1].cp1,
|
|
|
|
cp2: c2.ops[1].cp2,
|
2021-04-24 10:16:31 +02:00
|
|
|
end: c2.ops[1].to,
|
|
|
|
},
|
2019-08-03 15:03:33 +02:00
|
|
|
]
|
2019-02-17 21:40:26 +01:00
|
|
|
}
|
|
|
|
|
2018-08-23 15:57:23 +02:00
|
|
|
/** Find where an (endless) line intersects with a certain X-value */
|
|
|
|
export function beamIntersectsX(from, to, x) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (from.x === to.x) return false // Vertical line
|
|
|
|
let top = new Point(x, -10)
|
|
|
|
let bottom = new Point(x, 10)
|
2018-08-14 16:18:16 +02:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
return beamsIntersect(from, to, top, bottom)
|
2018-08-14 16:18:16 +02:00
|
|
|
}
|
|
|
|
|
2018-08-23 15:57:23 +02:00
|
|
|
/** Find where an (endless) line intersects with a certain Y-value */
|
|
|
|
export function beamIntersectsY(from, to, y) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (from.y === to.y) return false // Horizontal line
|
|
|
|
let left = new Point(-10, y)
|
|
|
|
let right = new Point(10, y)
|
2018-07-19 14:02:04 +00:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
return beamsIntersect(from, to, left, right)
|
2018-07-19 14:02:04 +00:00
|
|
|
}
|
|
|
|
|
2018-08-01 14:55:54 +02:00
|
|
|
/** Convert value in mm to cm or imperial units */
|
2019-08-03 15:03:33 +02:00
|
|
|
export function units(value, to = 'metric') {
|
2020-07-12 15:10:18 +02:00
|
|
|
if (to === 'imperial') return round(value / 25.4) + '"'
|
2019-08-03 15:03:33 +02:00
|
|
|
else return round(value / 10) + 'cm'
|
2018-08-01 14:55:54 +02:00
|
|
|
}
|
2018-08-21 13:49:12 +02:00
|
|
|
|
2018-08-23 15:57:23 +02:00
|
|
|
/** Find where a curve intersects with line */
|
|
|
|
export function lineIntersectsCurve(start, end, from, cp1, cp2, to) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let intersections = []
|
2018-08-21 13:49:12 +02:00
|
|
|
let bz = new Bezier(
|
|
|
|
{ x: from.x, y: from.y },
|
|
|
|
{ x: cp1.x, y: cp1.y },
|
|
|
|
{ x: cp2.x, y: cp2.y },
|
|
|
|
{ x: to.x, y: to.y }
|
2019-08-03 15:03:33 +02:00
|
|
|
)
|
2018-08-21 13:49:12 +02:00
|
|
|
let line = {
|
|
|
|
p1: { x: start.x, y: start.y },
|
2021-04-24 10:16:31 +02:00
|
|
|
p2: { x: end.x, y: end.y },
|
2019-08-03 15:03:33 +02:00
|
|
|
}
|
2018-08-21 13:49:12 +02:00
|
|
|
for (let t of bz.intersects(line)) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let isect = bz.get(t)
|
|
|
|
intersections.push(new Point(isect.x, isect.y))
|
2018-08-21 13:49:12 +02:00
|
|
|
}
|
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
if (intersections.length === 0) return false
|
|
|
|
else if (intersections.length === 1) return intersections[0]
|
|
|
|
else return intersections
|
2018-08-21 13:49:12 +02:00
|
|
|
}
|
|
|
|
|
2019-02-17 21:40:26 +01:00
|
|
|
/** Find where a curve intersects with a given X-value */
|
|
|
|
export function curveIntersectsX(from, cp1, cp2, to, x) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let start = new Point(x, -10000)
|
|
|
|
let end = new Point(x, 10000)
|
|
|
|
return lineIntersectsCurve(start, end, from, cp1, cp2, to)
|
2019-02-17 21:40:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Find where a curve intersects with a given Y-value */
|
|
|
|
export function curveIntersectsY(from, cp1, cp2, to, y) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let start = new Point(-10000, y)
|
|
|
|
let end = new Point(10000, y)
|
|
|
|
return lineIntersectsCurve(start, end, from, cp1, cp2, to)
|
2019-02-17 21:40:26 +01:00
|
|
|
}
|
|
|
|
|
2018-08-23 15:57:23 +02:00
|
|
|
/** Find where a curve intersects with another curve */
|
2019-08-03 15:03:33 +02:00
|
|
|
export function curvesIntersect(fromA, cp1A, cp2A, toA, fromB, cp1B, cp2B, toB) {
|
|
|
|
let precision = 0.005 // See https://github.com/Pomax/bezierjs/issues/99
|
|
|
|
let intersections = []
|
2018-08-21 13:49:12 +02:00
|
|
|
let curveA = new Bezier(
|
|
|
|
{ x: fromA.x, y: fromA.y },
|
|
|
|
{ x: cp1A.x, y: cp1A.y },
|
|
|
|
{ x: cp2A.x, y: cp2A.y },
|
|
|
|
{ x: toA.x, y: toA.y }
|
2019-08-03 15:03:33 +02:00
|
|
|
)
|
2018-08-21 13:49:12 +02:00
|
|
|
let curveB = new Bezier(
|
|
|
|
{ x: fromB.x, y: fromB.y },
|
|
|
|
{ x: cp1B.x, y: cp1B.y },
|
|
|
|
{ x: cp2B.x, y: cp2B.y },
|
|
|
|
{ x: toB.x, y: toB.y }
|
2019-08-03 15:03:33 +02:00
|
|
|
)
|
2018-08-21 13:49:12 +02:00
|
|
|
|
|
|
|
for (let tvalues of curveA.intersects(curveB, precision)) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let intersection = curveA.get(tvalues.substr(0, tvalues.indexOf('/')))
|
|
|
|
intersections.push(new Point(intersection.x, intersection.y))
|
2018-08-21 13:49:12 +02:00
|
|
|
}
|
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
if (intersections.length === 0) return false
|
|
|
|
else if (intersections.length === 1) return intersections.shift()
|
2018-08-21 13:49:12 +02:00
|
|
|
else {
|
2019-08-03 15:03:33 +02:00
|
|
|
let unique = []
|
2018-08-21 13:49:12 +02:00
|
|
|
for (let i of intersections) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let dupe = false
|
2018-08-21 13:49:12 +02:00
|
|
|
for (let u of unique) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (i.sitsRoughlyOn(u)) dupe = true
|
2018-08-21 13:49:12 +02:00
|
|
|
}
|
2019-08-03 15:03:33 +02:00
|
|
|
if (!dupe) unique.push(i)
|
2018-08-21 13:49:12 +02:00
|
|
|
}
|
2019-08-03 15:03:33 +02:00
|
|
|
return unique
|
2018-08-21 13:49:12 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-23 15:57:23 +02:00
|
|
|
|
|
|
|
/** Find the intersections between two circles */
|
2019-08-03 15:03:33 +02:00
|
|
|
export function circlesIntersect(c1, r1, c2, r2, sort = 'x') {
|
|
|
|
let dx = c1.dx(c2)
|
|
|
|
let dy = c1.dy(c2)
|
|
|
|
let dist = c1.dist(c2)
|
2018-08-23 15:57:23 +02:00
|
|
|
// Check for edge cases
|
2019-08-03 15:03:33 +02:00
|
|
|
if (dist > parseFloat(r1) + parseFloat(r2)) return false // Circles do not intersect
|
|
|
|
if (dist < parseFloat(r2) - parseFloat(r1)) return false // One circle is contained in the other
|
|
|
|
if (dist === 0 && r1 === r2) return false // Two circles are identical
|
|
|
|
let chorddistance = (Math.pow(r1, 2) - Math.pow(r2, 2) + Math.pow(dist, 2)) / (2 * dist)
|
|
|
|
let halfchordlength = Math.sqrt(Math.pow(r1, 2) - Math.pow(chorddistance, 2))
|
|
|
|
let chordmidpointx = c1.x + (chorddistance * dx) / dist
|
|
|
|
let chordmidpointy = c1.y + (chorddistance * dy) / dist
|
2018-08-23 15:57:23 +02:00
|
|
|
let i1 = new Point(
|
|
|
|
chordmidpointx + (halfchordlength * dy) / dist,
|
|
|
|
chordmidpointy - (halfchordlength * dx) / dist
|
2019-08-03 15:03:33 +02:00
|
|
|
)
|
2018-08-23 15:57:23 +02:00
|
|
|
let i2 = new Point(
|
|
|
|
chordmidpointx - (halfchordlength * dy) / dist,
|
|
|
|
chordmidpointy + (halfchordlength * dx) / dist
|
2019-08-03 15:03:33 +02:00
|
|
|
)
|
2018-08-23 15:57:23 +02:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
if ((sort === 'x' && i1.x <= i2.x) || (sort === 'y' && i1.y <= i2.y)) return [i1, i2]
|
|
|
|
else return [i2, i1]
|
2018-08-23 15:57:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Find the intersections between a beam and a circle */
|
2019-08-03 15:03:33 +02:00
|
|
|
export function beamIntersectsCircle(c, r, p1, p2, sort = 'x') {
|
|
|
|
let dx = p2.x - p1.x
|
|
|
|
let dy = p2.y - p1.y
|
|
|
|
let A = Math.pow(dx, 2) + Math.pow(dy, 2)
|
|
|
|
let B = 2 * (dx * (p1.x - c.x) + dy * (p1.y - c.y))
|
|
|
|
let C = Math.pow(p1.x - c.x, 2) + Math.pow(p1.y - c.y, 2) - Math.pow(r, 2)
|
2018-08-23 15:57:23 +02:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
let det = Math.pow(B, 2) - 4 * A * C
|
2018-08-23 15:57:23 +02:00
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
if (A <= 0.0000001 || det < 0) return false
|
2018-08-23 15:57:23 +02:00
|
|
|
// No real solutions
|
|
|
|
else if (det === 0) {
|
|
|
|
// One solution
|
2019-08-03 15:03:33 +02:00
|
|
|
let t = (-1 * B) / (2 * A)
|
|
|
|
let i1 = new Point(p1.x + t * dx, p1.y + t * dy)
|
|
|
|
return [i1]
|
2018-08-23 15:57:23 +02:00
|
|
|
} else {
|
|
|
|
// Two solutions
|
2019-08-03 15:03:33 +02:00
|
|
|
let t = (-1 * B + Math.sqrt(det)) / (2 * A)
|
|
|
|
let i1 = new Point(p1.x + t * dx, p1.y + t * dy)
|
|
|
|
t = (-1 * B - Math.sqrt(det)) / (2 * A)
|
|
|
|
let i2 = new Point(p1.x + t * dx, p1.y + t * dy)
|
|
|
|
if ((sort === 'x' && i1.x <= i2.x) || (sort === 'y' && i1.y <= i2.y)) return [i1, i2]
|
|
|
|
else return [i2, i1]
|
2018-08-23 15:57:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/** Find the intersections between a line and a circle */
|
2019-08-03 15:03:33 +02:00
|
|
|
export function lineIntersectsCircle(c, r, p1, p2, sort = 'x') {
|
|
|
|
let intersections = beamIntersectsCircle(c, r, p1, p2, sort)
|
|
|
|
if (intersections === false) return false
|
2018-08-23 15:57:23 +02:00
|
|
|
else {
|
|
|
|
if (intersections.length === 1) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if (pointOnLine(p1, p2, intersections[0])) return intersections
|
|
|
|
else return false
|
2018-08-23 15:57:23 +02:00
|
|
|
} else {
|
2019-08-03 15:03:33 +02:00
|
|
|
let i1 = intersections[0]
|
|
|
|
let i2 = intersections[1]
|
|
|
|
if (!pointOnLine(p1, p2, i1, 5) && !pointOnLine(p1, p2, i2, 5)) return false
|
2018-08-23 15:57:23 +02:00
|
|
|
else if (pointOnLine(p1, p2, i1, 5) && pointOnLine(p1, p2, i2, 5)) {
|
2019-08-03 15:03:33 +02:00
|
|
|
if ((sort === 'x' && i1.x <= i2.x) || (sort === 'y' && i1.y <= i2.y)) return [i1, i2]
|
|
|
|
else return [i2, i1]
|
|
|
|
} else if (pointOnLine(p1, p2, i1, 5)) return [i1]
|
|
|
|
else if (pointOnLine(p1, p2, i2, 5)) return [i2]
|
2018-08-23 15:57:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-31 09:44:12 +02:00
|
|
|
|
2018-09-03 12:07:02 +02:00
|
|
|
export function curveEdge(curve, edge, steps = 500) {
|
2019-08-03 15:03:33 +02:00
|
|
|
let x = Infinity
|
|
|
|
let y = Infinity
|
|
|
|
let p
|
|
|
|
if (edge === 'bottom') y = -Infinity
|
|
|
|
if (edge === 'right') x = -Infinity
|
2018-09-03 12:07:02 +02:00
|
|
|
for (let i = 0; i < steps; i++) {
|
2019-08-03 15:03:33 +02:00
|
|
|
p = curve.get(i / steps)
|
2018-09-03 12:07:02 +02:00
|
|
|
if (
|
2019-08-03 15:03:33 +02:00
|
|
|
(edge === 'top' && p.y < y) ||
|
|
|
|
(edge === 'bottom' && p.y > y) ||
|
|
|
|
(edge === 'right' && p.x > x) ||
|
|
|
|
(edge === 'left' && p.x < x)
|
2018-09-03 12:07:02 +02:00
|
|
|
) {
|
2019-08-03 15:03:33 +02:00
|
|
|
x = p.x
|
|
|
|
y = p.y
|
2018-09-03 12:07:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-03 15:03:33 +02:00
|
|
|
return new Point(x, y)
|
2018-09-03 12:07:02 +02:00
|
|
|
}
|
|
|
|
|
2018-08-31 09:44:12 +02:00
|
|
|
/**
|
|
|
|
* Calculates scale factor based on stretch factor
|
|
|
|
*
|
|
|
|
* The way people measure stretch intuitively is
|
|
|
|
* different from the way we handle stretch in code.
|
|
|
|
* When people say '25% stretch' they mean that
|
|
|
|
* 10cm fabric should get stretched to 12.5cm fabric.
|
|
|
|
* In our code, that means we need to scale things by 80%.
|
|
|
|
*
|
|
|
|
* This method does that calculation.
|
|
|
|
*/
|
|
|
|
export function stretchToScale(stretch) {
|
2019-08-03 15:03:33 +02:00
|
|
|
return 1 / (1 + parseFloat(stretch))
|
2018-08-31 09:44:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function round(value) {
|
2019-08-03 15:03:33 +02:00
|
|
|
return Math.round(value * 1e2) / 1e2
|
2018-08-31 09:44:12 +02:00
|
|
|
}
|
2018-09-22 10:41:51 +02:00
|
|
|
|
2020-05-30 14:02:37 +02:00
|
|
|
export function sampleStyle(run, runs, styles = false) {
|
|
|
|
return styles && Array.isArray(styles) && styles.length > 0
|
|
|
|
? styles[run % styles.length]
|
|
|
|
: `stroke: hsl(${(run - 1) * (330 / runs)}, 100%, 35%);`
|
2018-09-22 10:41:51 +02:00
|
|
|
}
|
2019-02-17 21:40:26 +01:00
|
|
|
|
|
|
|
export function deg2rad(degrees) {
|
2019-08-03 15:03:33 +02:00
|
|
|
return degrees * (Math.PI / 180)
|
2019-02-17 21:40:26 +01:00
|
|
|
}
|
2019-07-11 16:49:02 +02:00
|
|
|
|
|
|
|
export function rad2deg(radians) {
|
2019-08-03 15:03:33 +02:00
|
|
|
return (radians / Math.PI) * 180
|
2019-07-11 16:49:02 +02:00
|
|
|
}
|
2020-04-18 11:38:08 +02:00
|
|
|
|
|
|
|
// Export bezier-js so plugins can use it
|
2020-11-04 20:06:19 +01:00
|
|
|
export { Bezier }
|
2021-09-15 20:20:59 +02:00
|
|
|
|
|
|
|
export function pctBasedOn(measurement) {
|
|
|
|
return {
|
|
|
|
toAbs: (val, { measurements }) => measurements[measurement] * val,
|
2021-10-08 17:32:12 +02:00
|
|
|
fromAbs: (val, { measurements }) => Math.round((10 * val) / measurements[measurement]) / 10,
|
2021-09-15 20:20:59 +02:00
|
|
|
}
|
|
|
|
}
|
2022-07-02 20:05:31 +02:00
|
|
|
|
|
|
|
/** Generates the transform attributes needed for a given part */
|
|
|
|
export const generatePartTransform = (x, y, rotate, flipX, flipY, part) => {
|
|
|
|
const center = {
|
|
|
|
x: part.topLeft.x + (part.bottomRight.x - part.topLeft.x)/2,
|
|
|
|
y: part.topLeft.y + (part.bottomRight.y - part.topLeft.y)/2,
|
|
|
|
}
|
|
|
|
|
|
|
|
const transforms = [`translate(${x},${y})`]
|
|
|
|
if (flipX) transforms.push(
|
|
|
|
'scale(-1, 1)',
|
|
|
|
)
|
|
|
|
if (flipY) transforms.push(
|
|
|
|
'scale(1, -1)',
|
|
|
|
)
|
|
|
|
if (rotate) transforms.push(
|
|
|
|
`rotate(${rotate})`
|
|
|
|
)
|
|
|
|
|
|
|
|
return {
|
|
|
|
transform: transforms.join(' '),
|
|
|
|
'transform-origin': `${center.x} ${center.y}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|