rabbit-ear
Version:
origami design library
109 lines (105 loc) • 4.24 kB
JavaScript
/* Rabbit Ear 0.9.4 alpha 2024-04-20 (c) Kraft, GNU GPLv3 License */
import { TWO_PI, EPSILON } from './constant.js';
import { angleToVector, vectorToAngle } from './convert.js';
import { epsilonEqual } from './compare.js';
import { normalize2, subtract2, cross2, distance2 } from './vector.js';
const isCounterClockwiseBetween = (angle, floor, ceiling) => {
while (ceiling < floor) { ceiling += TWO_PI; }
while (angle > floor) { angle -= TWO_PI; }
while (angle < floor) { angle += TWO_PI; }
return angle < ceiling;
};
const clockwiseAngleRadians = (a, b) => {
while (a < 0) { a += TWO_PI; }
while (b < 0) { b += TWO_PI; }
while (a > TWO_PI) { a -= TWO_PI; }
while (b > TWO_PI) { b -= TWO_PI; }
const a_b = a - b;
return (a_b >= 0)
? a_b
: TWO_PI - (b - a);
};
const counterClockwiseAngleRadians = (a, b) => {
while (a < 0) { a += TWO_PI; }
while (b < 0) { b += TWO_PI; }
while (a > TWO_PI) { a -= TWO_PI; }
while (b > TWO_PI) { b -= TWO_PI; }
const b_a = b - a;
return (b_a >= 0)
? b_a
: TWO_PI - (a - b);
};
const clockwiseAngle2 = (a, b) => {
const dotProduct = b[0] * a[0] + b[1] * a[1];
const determinant = b[0] * a[1] - b[1] * a[0];
let angle = Math.atan2(determinant, dotProduct);
if (angle < 0) { angle += TWO_PI; }
return angle;
};
const counterClockwiseAngle2 = (a, b) => {
const dotProduct = a[0] * b[0] + a[1] * b[1];
const determinant = a[0] * b[1] - a[1] * b[0];
let angle = Math.atan2(determinant, dotProduct);
if (angle < 0) { angle += TWO_PI; }
return angle;
};
const clockwiseBisect2 = (a, b) => (
angleToVector(vectorToAngle(a) - clockwiseAngle2(a, b) / 2)
);
const counterClockwiseBisect2 = (a, b) => (
angleToVector(vectorToAngle(a) + counterClockwiseAngle2(a, b) / 2)
);
const clockwiseSubsectRadians = (angleA, angleB, divisions) => {
const angle = clockwiseAngleRadians(angleA, angleB) / divisions;
return Array.from(Array(divisions - 1))
.map((_, i) => angleA + angle * (i + 1));
};
const counterClockwiseSubsectRadians = (angleA, angleB, divisions) => {
const angle = counterClockwiseAngleRadians(angleA, angleB) / divisions;
return Array.from(Array(divisions - 1))
.map((_, i) => angleA + angle * (i + 1));
};
const clockwiseSubsect2 = (vectorA, vectorB, divisions) => {
const angleA = Math.atan2(vectorA[1], vectorA[0]);
const angleB = Math.atan2(vectorB[1], vectorB[0]);
return clockwiseSubsectRadians(angleA, angleB, divisions)
.map(angleToVector);
};
const counterClockwiseSubsect2 = (vectorA, vectorB, divisions) => {
const angleA = Math.atan2(vectorA[1], vectorA[0]);
const angleB = Math.atan2(vectorB[1], vectorB[0]);
return counterClockwiseSubsectRadians(angleA, angleB, divisions)
.map(angleToVector);
};
const counterClockwiseOrderRadians = (radians) => {
const counter_clockwise = radians
.map((_, i) => i)
.sort((a, b) => radians[a] - radians[b]);
return counter_clockwise
.slice(counter_clockwise.indexOf(0), counter_clockwise.length)
.concat(counter_clockwise.slice(0, counter_clockwise.indexOf(0)));
};
const counterClockwiseOrder2 = (vectors) => (
counterClockwiseOrderRadians(vectors.map(vectorToAngle))
);
const counterClockwiseSectorsRadians = (radians) => (
counterClockwiseOrderRadians(radians)
.map(i => radians[i])
.map((rad, i, arr) => [rad, arr[(i + 1) % arr.length]])
.map(pair => counterClockwiseAngleRadians(pair[0], pair[1]))
);
const counterClockwiseSectors2 = (vectors) => (
counterClockwiseSectorsRadians(vectors.map(vectorToAngle))
);
const threePointTurnDirection = (p0, p1, p2, epsilon = EPSILON) => {
const v = normalize2(subtract2(p1, p0));
const u = normalize2(subtract2(p2, p0));
const cross = cross2(v, u);
if (!epsilonEqual(cross, 0, epsilon)) {
return Math.sign(cross);
}
return epsilonEqual(distance2(p0, p1) + distance2(p1, p2), distance2(p0, p2))
? 0
: undefined;
};
export { clockwiseAngle2, clockwiseAngleRadians, clockwiseBisect2, clockwiseSubsect2, clockwiseSubsectRadians, counterClockwiseAngle2, counterClockwiseAngleRadians, counterClockwiseBisect2, counterClockwiseOrder2, counterClockwiseOrderRadians, counterClockwiseSectors2, counterClockwiseSectorsRadians, counterClockwiseSubsect2, counterClockwiseSubsectRadians, isCounterClockwiseBetween, threePointTurnDirection };