New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

perfect-arrows

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

perfect-arrows - npm Package Compare versions

Comparing version 0.2.0 to 0.2.1

dist/lib/getBoxToBoxArrow.d.ts

4

CHANGELOG.md

@@ -0,1 +1,5 @@

# 0.2.1
- Adds box to box algorithm.
# 0.2.0

@@ -2,0 +6,0 @@

4

dist/index.d.ts

@@ -1,2 +0,2 @@

import { getArrow, ArrowOptions } from "./lib";
export { getArrow, ArrowOptions };
import { getArrow, getBoxToBoxArrow, ArrowOptions } from "./lib";
export { getArrow, getBoxToBoxArrow, ArrowOptions };

@@ -13,2 +13,3 @@ export declare type ArrowOptions = {

* getArrow
* Get the points for a linking line between two points.
* @description Draw an arrow between two points.

@@ -15,0 +16,0 @@ * @param x0 The x position of the "from" point.

import getArrow, { ArrowOptions } from "./getArrow";
export { getArrow, ArrowOptions };
import getBoxToBoxArrow from "./getBoxToBoxArrow";
export { getArrow, ArrowOptions, getBoxToBoxArrow };
/**
* Modulate a value between two ranges
* Modulate a value between two ranges.
* @param value

@@ -11,7 +11,7 @@ * @param a from [low, high]

* Rotate a point around a center.
* @param x
* @param y
* @param cx
* @param cy
* @param angle
* @param x The x-axis coordinate of the point.
* @param y The y-axis coordinate of the point.
* @param cx The x-axis coordinate of the point to rotate round.
* @param cy The y-axis coordinate of the point to rotate round.
* @param angle The distance (in radians) to rotate.
*/

@@ -21,6 +21,6 @@ export declare function rotatePoint(x: number, y: number, cx: number, cy: number, angle: number): number[];

* Get the distance between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -30,6 +30,6 @@ export declare function getDistance(x0: number, y0: number, x1: number, y1: number): number;

* Get an angle (radians) between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -47,6 +47,6 @@ export declare function getAngle(x0: number, y0: number, x1: number, y1: number): number;

* Get a point between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
* @param d Normalized

@@ -57,4 +57,4 @@ */

* Get the sector of an angle (e.g. quadrant, octant)
* @param a angle
* @param s number of sectors
* @param a The angle to check.
* @param s The number of sectors to check.
*/

@@ -64,2 +64,106 @@ export declare function getSector(a: number, s?: number): number;

* Get a normal value representing how close two points are from being at a 45 degree angle.
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/
export declare function getAngliness(x0: number, y0: number, x1: number, y1: number): number;
/**
* Get the points at which an ellipse intersects a rectangle.
* @param x
* @param y
* @param w
* @param h
* @param cx
* @param cy
* @param rx
* @param ry
* @param angle
*/
export declare function getEllipseRectangleIntersectionPoints(x: number, y: number, w: number, h: number, cx: number, cy: number, rx: number, ry: number, angle: number): number[][];
/**
* Find the point(s) where a line segment intersects an ellipse.
* @param x0 The x-axis coordinate of the line's start point.
* @param y0 The y-axis coordinate of the line's start point.
* @param x1 The x-axis coordinate of the line's end point.
* @param y1 The y-axis coordinate of the line's end point.
* @param cx The x-axis (horizontal) coordinate of the ellipse's center.
* @param cy The y-axis (vertical) coordinate of the ellipse's center.
* @param rx The ellipse's major-axis radius. Must be non-negative.
* @param ry The ellipse's minor-axis radius. Must be non-negative.
* @param rotation The rotation of the ellipse, expressed in radians.
* @param segment_only When true, will test the segment as a line (of infinite length).
*/
export declare function getEllipseSegmentIntersections(x0: number, y0: number, x1: number, y1: number, cx: number, cy: number, rx: number, ry: number, rotation?: number, segment_only?: boolean): number[][];
/**
* Check whether two rectangles will collide (overlap).
* @param x0 The x-axis coordinate of the first rectangle.
* @param y0 The y-axis coordinate of the first rectangle.
* @param w0 The width of the first rectangle.
* @param h0 The height of the first rectangle.
* @param x1 The x-axis coordinate of the second rectangle.
* @param y1 The y-axis coordinate of the second rectangle.
* @param w1 The width of the second rectangle.
* @param h1 The height of the second rectangle.
*/
export declare function doRectanglesCollide(x0: number, y0: number, w0: number, h0: number, x1: number, y1: number, w1: number, h1: number): boolean;
/**
* Find the point(s) where a segment intersects a rectangle.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of the segment's starting point.
* @param x1 The x-axis coordinate of the segment's ending point.
* @param y1 The y-axis coordinate of the segment's ending point.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
*/
export declare function getSegmentRectangleIntersectionPoints(x0: number, y0: number, x1: number, y1: number, x: number, y: number, w: number, h: number): number[][];
/**
* Find the point, if any, where two segments intersect.
* @param x0 The x-axis coordinate of the first segment's starting point.
* @param y0 The y-axis coordinate of the first segment's starting point.
* @param x1 The x-axis coordinate of the first segment's ending point.
* @param y1 The y-axis coordinate of the first segment's ending point.
* @param x2 The x-axis coordinate of the second segment's starting point.
* @param y2 The y-axis coordinate of the second segment's starting point.
* @param x3 The x-axis coordinate of the second segment's ending point.
* @param y3 The y-axis coordinate of the second segment's ending point.
*/
export declare function getSegmentSegmentIntersection(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number[] | undefined;
/**
* Get the intersection points between a line segment and a rectangle with rounded corners.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
* @param r The corner radius of the rectangle.
*/
export declare function getSegmentRoundedRectangleIntersectionPoints(x0: number, y0: number, x1: number, y1: number, x: number, y: number, w: number, h: number, r: number): number[][];
/**
* Get the point(s) where a line segment intersects a circle.
* @param cx The x-axis coordinate of the circle's center.
* @param cy The y-axis coordinate of the circle's center.
* @param r The circle's radius.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
*/
export declare function getSegmentCircleIntersections(cx: number, cy: number, r: number, x0: number, y0: number, x1: number, y1: number): number[][];
/**
* Normalize an angle (in radians)
* @param radians The radians quantity to normalize.
*/
export declare function normalizeAngle(radians: number): number;
/**
*
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param w
* @param h
* @param x0

@@ -70,2 +174,19 @@ * @param y0

*/
export declare function getAngliness(x0: number, y0: number, x1: number, y1: number): number;
export declare function getRayRectangleIntersectionPoints(ox: number, oy: number, dx: number, dy: number, x: number, y: number, w: number, h: number): number[][];
/**
* Get the point at which a ray intersects a segment.
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param dx The x-axis delta of the angle.
* @param dy The y-axis delta of the angle.
* @param x0 The x-axis coordinate of the segment's start point.
* @param y0 The y-axis coordinate of the segment's start point.
* @param x1 The x-axis coordinate of the segment's end point.
* @param y1 The y-axis coordinate of the segment's end point.
*/
export declare function getRaySegmentIntersection(x: number, y: number, dx: number, dy: number, x0: number, y0: number, x1: number, y1: number): number[] | undefined;
/**
* Get the normalized delta (x and y) for an angle.
* @param angle The angle in radians
*/
export declare function getDelta(angle: number): number[];

@@ -6,3 +6,3 @@ 'use strict';

/**
* Modulate a value between two ranges
* Modulate a value between two ranges.
* @param value

@@ -33,7 +33,7 @@ * @param a from [low, high]

* Rotate a point around a center.
* @param x
* @param y
* @param cx
* @param cy
* @param angle
* @param x The x-axis coordinate of the point.
* @param y The y-axis coordinate of the point.
* @param cx The x-axis coordinate of the point to rotate round.
* @param cy The y-axis coordinate of the point to rotate round.
* @param angle The distance (in radians) to rotate.
*/

@@ -52,6 +52,6 @@

* Get the distance between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -64,6 +64,6 @@

* Get an angle (radians) between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -87,6 +87,6 @@

* Get a point between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
* @param d Normalized

@@ -104,4 +104,4 @@ */

* Get the sector of an angle (e.g. quadrant, octant)
* @param a angle
* @param s number of sectors
* @param a The angle to check.
* @param s The number of sectors to check.
*/

@@ -118,2 +118,207 @@

* Get a normal value representing how close two points are from being at a 45 degree angle.
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/
function getAngliness(x0, y0, x1, y1) {
return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2));
}
/**
* Check whether two rectangles will collide (overlap).
* @param x0 The x-axis coordinate of the first rectangle.
* @param y0 The y-axis coordinate of the first rectangle.
* @param w0 The width of the first rectangle.
* @param h0 The height of the first rectangle.
* @param x1 The x-axis coordinate of the second rectangle.
* @param y1 The y-axis coordinate of the second rectangle.
* @param w1 The width of the second rectangle.
* @param h1 The height of the second rectangle.
*/
function doRectanglesCollide(x0, y0, w0, h0, x1, y1, w1, h1) {
return !(x0 >= x1 + w1 || x1 >= x0 + w0 || y0 >= y1 + h1 || y1 >= y0 + h0);
}
/**
* Find the point(s) where a segment intersects a rectangle.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of the segment's starting point.
* @param x1 The x-axis coordinate of the segment's ending point.
* @param y1 The y-axis coordinate of the segment's ending point.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
*/
function getSegmentRectangleIntersectionPoints(x0, y0, x1, y1, x, y, w, h) {
var points = [];
for (var _i2 = 0, _arr2 = [[x, y, x + w, y], [x + w, y, x + w, y + h], [x + w, y + h, x, y + h], [x, y + h, x, y]]; _i2 < _arr2.length; _i2++) {
var _arr2$_i = _arr2[_i2],
px0 = _arr2$_i[0],
py0 = _arr2$_i[1],
px1 = _arr2$_i[2],
py1 = _arr2$_i[3];
var ints = getSegmentSegmentIntersection(px0, py0, px1, py1, x0, y0, x1, y1);
if (ints) {
points.push(ints);
}
}
return points;
}
/**
* Find the point, if any, where two segments intersect.
* @param x0 The x-axis coordinate of the first segment's starting point.
* @param y0 The y-axis coordinate of the first segment's starting point.
* @param x1 The x-axis coordinate of the first segment's ending point.
* @param y1 The y-axis coordinate of the first segment's ending point.
* @param x2 The x-axis coordinate of the second segment's starting point.
* @param y2 The y-axis coordinate of the second segment's starting point.
* @param x3 The x-axis coordinate of the second segment's ending point.
* @param y3 The y-axis coordinate of the second segment's ending point.
*/
function getSegmentSegmentIntersection(x0, y0, x1, y1, x2, y2, x3, y3) {
var denom = (y3 - y2) * (x1 - x0) - (x3 - x2) * (y1 - y0);
var numeA = (x3 - x2) * (y0 - y2) - (y3 - y2) * (x0 - x2);
var numeB = (x1 - x0) * (y0 - y2) - (y1 - y0) * (x0 - x2);
if (denom === 0) {
if (numeA === 0 && numeB === 0) {
return undefined; // Colinear
}
return undefined; // Parallel
}
var uA = numeA / denom;
var uB = numeB / denom;
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
return [x0 + uA * (x1 - x0), y0 + uA * (y1 - y0)];
}
return undefined; // No intersection
}
/**
* Get the intersection points between a line segment and a rectangle with rounded corners.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
* @param r The corner radius of the rectangle.
*/
function getSegmentRoundedRectangleIntersectionPoints(x0, y0, x1, y1, x, y, w, h, r) {
var mx = x + w,
my = y + h,
rx = x + r,
ry = y + r,
mrx = x + w - r,
mry = y + h - r;
var segments = [[x, mry, x, ry, x, y], [rx, y, mrx, y, mx, y], [mx, ry, mx, mry, mx, my], [mrx, my, rx, my, x, my]];
var corners = [[rx, ry, Math.PI, Math.PI * 1.5], [mrx, ry, Math.PI * 1.5, Math.PI * 2], [mrx, mry, 0, Math.PI * 0.5], [rx, mry, Math.PI * 0.5, Math.PI]];
var points = [];
segments.forEach(function (segment, i) {
var px0 = segment[0],
py0 = segment[1],
px1 = segment[2],
py1 = segment[3];
var _corners$i = corners[i],
cx = _corners$i[0],
cy = _corners$i[1],
as = _corners$i[2],
ae = _corners$i[3];
getSegmentCircleIntersections(cx, cy, r, x0, y0, x1, y1).filter(function (pt) {
var pointAngle = normalizeAngle(getAngle(cx, cy, pt[0], pt[1]));
return pointAngle > as && pointAngle < ae;
}).forEach(function (pt) {
return points.push(pt);
});
var segmentInt = getSegmentSegmentIntersection(x0, y0, x1, y1, px0, py0, px1, py1);
if (!!segmentInt) {
points.push(segmentInt);
}
});
return points;
}
/**
* Get the point(s) where a line segment intersects a circle.
* @param cx The x-axis coordinate of the circle's center.
* @param cy The y-axis coordinate of the circle's center.
* @param r The circle's radius.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
*/
function getSegmentCircleIntersections(cx, cy, r, x0, y0, x1, y1) {
var b,
c,
d,
u1,
u2,
ret,
retP1,
retP2,
v1 = [x1 - x0, y1 - y0],
v2 = [x0 - cx, y0 - cy];
b = v1[0] * v2[0] + v1[1] * v2[1];
c = 2 * (v1[0] * v1[0] + v1[1] * v1[1]);
b *= -2;
d = Math.sqrt(b * b - 2 * c * (v2[0] * v2[0] + v2[1] * v2[1] - r * r));
if (isNaN(d)) {
// no intercept
return [];
}
u1 = (b - d) / c; // these represent the unit distance of point one and two on the line
u2 = (b + d) / c;
retP1 = []; // return points
retP2 = [];
ret = []; // return array
if (u1 <= 1 && u1 >= 0) {
// add point if on the line segment
retP1[0] = x0 + v1[0] * u1;
retP1[1] = y0 + v1[1] * u1;
ret[0] = retP1;
}
if (u2 <= 1 && u2 >= 0) {
// second add point if on the line segment
retP2[0] = x0 + v1[0] * u2;
retP2[1] = y0 + v1[1] * u2;
ret[ret.length] = retP2;
}
return ret;
}
/**
* Normalize an angle (in radians)
* @param radians The radians quantity to normalize.
*/
function normalizeAngle(radians) {
return radians - Math.PI * 2 * Math.floor(radians / (Math.PI * 2));
}
/**
*
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param w
* @param h
* @param x0

@@ -125,8 +330,62 @@ * @param y0

function getAngliness(x0, y0, x1, y1) {
return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2));
function getRayRectangleIntersectionPoints(ox, oy, dx, dy, x, y, w, h) {
var points = [];
for (var _i3 = 0, _arr3 = [[x, y, x + w, y], [x + w, y, x + w, y + h], [x + w, y + h, x, y + h], [x, y + h, x, y]]; _i3 < _arr3.length; _i3++) {
var _arr3$_i = _arr3[_i3],
px0 = _arr3$_i[0],
py0 = _arr3$_i[1],
px1 = _arr3$_i[2],
py1 = _arr3$_i[3];
var ints = getRaySegmentIntersection(ox, oy, dx, dy, px0, py0, px1, py1);
if (ints) {
points.push(ints);
}
}
return points;
}
/**
* Get the point at which a ray intersects a segment.
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param dx The x-axis delta of the angle.
* @param dy The y-axis delta of the angle.
* @param x0 The x-axis coordinate of the segment's start point.
* @param y0 The y-axis coordinate of the segment's start point.
* @param x1 The x-axis coordinate of the segment's end point.
* @param y1 The y-axis coordinate of the segment's end point.
*/
function getRaySegmentIntersection(x, y, dx, dy, x0, y0, x1, y1) {
var r, s, d;
if (dy * (x1 - x0) !== dx * (y1 - y0)) {
d = dx * (y1 - y0) - dy * (x1 - x0);
if (d !== 0) {
r = ((y - y0) * (x1 - x0) - (x - x0) * (y1 - y0)) / d;
s = ((y - y0) * dx - (x - x0) * dy) / d;
if (r >= 0 && s >= 0 && s <= 1) {
return [x + r * dx, y + r * dy];
}
}
}
return undefined;
}
/**
* Get the normalized delta (x and y) for an angle.
* @param angle The angle in radians
*/
function getDelta(angle) {
return [Math.cos(angle), Math.sin(angle)];
}
/**
* getArrow
* Get the points for a linking line between two points.
* @description Draw an arrow between two points.

@@ -276,3 +535,161 @@ * @param x0 The x position of the "from" point.

/**
* getArrowBetweenBoxes
* Get the points for a linking line between two boxes.
* @param x0 The x-axis coordinate of the first box.
* @param y0 The y-axis coordinate of the first box.
* @param w0 The width of the first box.
* @param h0 The height of the first box.
* @param x1 The x-axis coordinate of the second box.
* @param y1 The y-axis coordinate of the second box.
* @param w1 The width of the second box.
* @param h1 The height of the second box.
* @param options
*/
function getBoxToBoxArrow(x0, y0, w0, h0, x1, y1, w1, h1, options) {
if (options === void 0) {
options = {};
}
var i0x, i0y, i1x, i1y;
var _options = options,
_options$bow = _options.bow,
bow = _options$bow === void 0 ? 0 : _options$bow,
_options$stretch = _options.stretch,
stretch = _options$stretch === void 0 ? 0.5 : _options$stretch,
_options$stretchMin = _options.stretchMin,
stretchMin = _options$stretchMin === void 0 ? 0 : _options$stretchMin,
_options$stretchMax = _options.stretchMax,
stretchMax = _options$stretchMax === void 0 ? 420 : _options$stretchMax,
_options$padStart = _options.padStart,
padStart = _options$padStart === void 0 ? 20 : _options$padStart,
_options$padEnd = _options.padEnd,
padEnd = _options$padEnd === void 0 ? 20 : _options$padEnd,
_options$flip = _options.flip,
flip = _options$flip === void 0 ? false : _options$flip,
_options$straights = _options.straights,
straights = _options$straights === void 0 ? true : _options$straights;
var cx0 = x0 + w0 / 2,
cy0 = y0 + h0 / 2,
cx1 = x1 + w1 / 2,
cy1 = y1 + h1 / 2,
px0 = x0 - padStart,
py0 = y0 - padStart,
pw0 = w0 + padStart * 2,
ph0 = h0 + padStart * 2,
px1 = x1 - padEnd,
py1 = y1 - padEnd,
pw1 = w1 + padEnd * 2,
ph1 = h1 + padEnd * 2;
var _getPointBetween = getPointBetween(cx0, cy0, cx1, cy1, 0.5),
mx = _getPointBetween[0],
my = _getPointBetween[1];
var angle = getAngle(cx0, cy0, cx1, cy1);
var angliness = getAngliness(cx0, cy0, cx1, cy1);
var minLength = Math.min(pw0, ph0, pw1, ph1) * 2;
var direct = getDistance(x0, y0, x1, y1);
var overflow = minLength - direct;
var isColliding = doRectanglesCollide(px0, py0, pw0, ph0, px1, py1, pw1, ph1);
if (straights && ([0, 1, Infinity].includes(angliness) || cx0 === cx1 || cy0 === cy1) && !isColliding) {
var _getSegmentRectangleI = getSegmentRectangleIntersectionPoints(cx0, cy0, cx1, cy1, px0, py0, pw0, ph0);
var _getSegmentRectangleI2 = _getSegmentRectangleI[0];
i0x = _getSegmentRectangleI2[0];
i0y = _getSegmentRectangleI2[1];
var _getSegmentRectangleI3 = getSegmentRectangleIntersectionPoints(cx0, cy0, cx1, cy1, px1, py1, pw1, ph1);
var _getSegmentRectangleI4 = _getSegmentRectangleI3[0];
i1x = _getSegmentRectangleI4[0];
i1y = _getSegmentRectangleI4[1];
return [i0x, i0y, mx, my, i1x, i1y, angle, angle + Math.PI, angle];
} // ⤜⤏ Arrow is an arc!
// Is the arc clockwise or counterclockwise?
var rot = (getSector(angle) % 2 === 0 ? 1 : -1) * (flip ? -1 : 1); // Calculate how much the line should "bow" away from center
var stretchEffect = mod(direct, [stretchMin, stretchMax], [1, 0], true);
var arc = bow + stretchEffect * stretch / 2; // Step 1 ⤜⤏ Find padded points.
// Get control point.
var _getPointBetween2 = getPointBetween(cx0, cy0, cx1, cy1, 0.5 - arc),
cx = _getPointBetween2[0],
cy = _getPointBetween2[1];
var _rotatePoint = rotatePoint(cx, cy, mx, my, Math.PI / 2 * rot);
cx = _rotatePoint[0];
cy = _rotatePoint[1];
if (overflow > 0) {
var _projectPoint = projectPoint(cx, cy, angle + Math.PI / 2 * -rot, overflow * arc);
cx = _projectPoint[0];
cy = _projectPoint[1];
} // Get padded start point.
var i0 = getSegmentRoundedRectangleIntersectionPoints(cx0, cy0, cx, cy, px0, py0, pw0, ph0, padStart); // Get padded end point.
var i1 = getSegmentRoundedRectangleIntersectionPoints(cx1, cy1, cx, cy, px1, py1, pw1, ph1, padEnd); // If we don't have intersections, or if the distance between the
// intersections is very small, use the backup point-finding stategy
if (!(i0[0] && i1[0]) || getDistance(i0[0][0], i0[0][1], i1[0][0], i1[0][1]) < padStart + padEnd) {
// Basically, shoot a ray based on the opposite angle between
// the two centers, and see where it intersects the rectangles.
// This part can definitely be improved!
var _getDelta = getDelta(angle + Math.PI),
dx = _getDelta[0],
dy = _getDelta[1];
var _getRayRectangleInter = getRayRectangleIntersectionPoints(cx0, cy0, dx, dy, px0, py0, pw0, ph0);
var _getRayRectangleInter2 = _getRayRectangleInter[0];
i0x = _getRayRectangleInter2[0];
i0y = _getRayRectangleInter2[1];
var _getRayRectangleInter3 = getRayRectangleIntersectionPoints(cx1, cy1, dx, dy, px1, py1, pw1, ph1);
var _getRayRectangleInter4 = _getRayRectangleInter3[0];
i1x = _getRayRectangleInter4[0];
i1y = _getRayRectangleInter4[1];
arc = (bow + stretchEffect * stretch) * -1;
} else {
var _i0$ = i0[0];
i0x = _i0$[0];
i0y = _i0$[1];
var _i1$ = i1[0];
i1x = _i1$[0];
i1y = _i1$[1];
arc = bow + stretchEffect * stretch;
} // Step 3 ⤜⤏ Calculate arrow points using same algorithm as getArrow
var _getPointBetween3 = getPointBetween(i0x, i0y, i1x, i1y, 0.5),
mx1 = _getPointBetween3[0],
my1 = _getPointBetween3[1];
var _getPointBetween4 = getPointBetween(i0x, i0y, i1x, i1y, 0.5 - arc);
cx = _getPointBetween4[0];
cy = _getPointBetween4[1];
var _rotatePoint2 = rotatePoint(cx, cy, mx1, my1, Math.PI / (2 * rot));
cx = _rotatePoint2[0];
cy = _rotatePoint2[1];
var as = getAngle(cx, cy, i0x, i0y);
var ae = getAngle(cx, cy, i1x, i1y);
return [i0x, i0y, cx, cy, i1x, i1y, ae, as, angle];
}
exports.getArrow = getArrow;
exports.getBoxToBoxArrow = getBoxToBoxArrow;
//# sourceMappingURL=perfect-arrows.cjs.development.js.map

@@ -1,2 +0,2 @@

"use strict";function t(t,r,n,i,a){var o=Math.sin(a),e=Math.cos(a),u=t-n,h=r-i;return[u*e-h*o+n,u*o+h*e+i]}function r(t,r,n,i){return Math.atan2(i-r,n-t)}function n(t,r,n,i){return[Math.cos(n)*i+t,Math.sin(n)*i+r]}function i(t,r,n,i,a){return void 0===a&&(a=.5),[t+(n-t)*a,r+(i-r)*a]}Object.defineProperty(exports,"__esModule",{value:!0}),exports.getArrow=function(a,o,e,u,h){void 0===h&&(h={});var M=h.bow,d=void 0===M?0:M,v=h.stretch,c=void 0===v?.5:v,f=h.stretchMin,s=void 0===f?0:f,p=h.stretchMax,l=void 0===p?420:p,x=h.padStart,I=void 0===x?0:x,P=h.padEnd,m=void 0===P?0:P,b=h.flip,y=void 0!==b&&b,g=h.straights,w=void 0===g||g,_=r(a,o,e,u),j=function(t,r,n,i){return Math.hypot(i-r,n-t)}(a,o,e,u),A=function(t,r,n,i){return Math.abs((n-t)/2/((i-r)/2))}(a,o,e,u);if(j<2*(I+m)||0===d&&0===c||w&&[0,1,Infinity].includes(A)){var E=Math.max(0,Math.min(j-I,I)),O=Math.max(0,Math.min(j-E,m)),S=n(a,o,_,E),k=S[0],q=S[1],z=n(e,u,_+Math.PI,O),B=z[0],C=z[1],D=i(k,q,B,C,.5);return[k,q,D[0],D[1],B,C,_,_,_]}var F,G=(0==(void 0===F&&(F=8),Math.floor(F*(.5+_/(2*Math.PI)%F))%2)?1:-1)*(y?-1:1),H=d+function(t,r,n,i){void 0===i&&(i=!1);var a=n[0]<n[1]?[n[0],n[1]]:[n[1],n[0]],o=a[0],e=a[1],u=n[0]+(t-r[0])/(r[1]-n[0])*(n[1]-n[0]);if(i){if(u<o)return o;if(u>e)return e}return u}(j,[s,l],[1,0],!0)*c,J=i(a,o,e,u,.5),K=J[0],L=J[1],N=i(a,o,e,u,.5-H),Q=N[0],R=N[1],T=t(Q,R,K,L,Math.PI/2*G),U=n(a,o,r(a,o,Q=T[0],R=T[1]),I),V=U[0],W=U[1],X=n(e,u,r(e,u,Q,R),m),Y=X[0],Z=X[1],$=r(Q,R,a,o),tt=r(Q,R,e,u),rt=i(V,W,Y,Z,.5),nt=rt[0],it=rt[1],at=i(V,W,Y,Z,.5-H),ot=at[0],et=at[1],ut=t(ot,et,nt,it,Math.PI/2*G),ht=i(Q,R,ot=ut[0],et=ut[1],.5);return[V,W,ht[0],ht[1],Y,Z,tt,$,_]};
"use strict";function t(t,r,n,a){void 0===a&&(a=!1);var i=n[0]<n[1]?[n[0],n[1]]:[n[1],n[0]],o=i[0],u=i[1],h=n[0]+(t-r[0])/(r[1]-n[0])*(n[1]-n[0]);if(a){if(h<o)return o;if(h>u)return u}return h}function r(t,r,n,a,i){var o=Math.sin(i),u=Math.cos(i),h=t-n,v=r-a;return[h*u-v*o+n,h*o+v*u+a]}function n(t,r,n,a){return Math.hypot(a-r,n-t)}function a(t,r,n,a){return Math.atan2(a-r,n-t)}function i(t,r,n,a){return[Math.cos(n)*a+t,Math.sin(n)*a+r]}function o(t,r,n,a,i){return void 0===i&&(i=.5),[t+(n-t)*i,r+(a-r)*i]}function u(t,r){return void 0===r&&(r=8),Math.floor(r*(.5+t/(2*Math.PI)%r))}function h(t,r,n,a){return Math.abs((n-t)/2/((a-r)/2))}function v(t,r,n,a,i,o,u,h){for(var v=[],f=0,M=[[i,o,i+u,o],[i+u,o,i+u,o+h],[i+u,o+h,i,o+h],[i,o+h,i,o]];f<M.length;f++){var c=M[f],d=e(c[0],c[1],c[2],c[3],t,r,n,a);d&&v.push(d)}return v}function e(t,r,n,a,i,o,u,h){var v=(h-o)*(n-t)-(u-i)*(a-r);if(0!==v){var e=((u-i)*(r-o)-(h-o)*(t-i))/v,f=((n-t)*(r-o)-(a-r)*(t-i))/v;return e>=0&&e<=1&&f>=0&&f<=1?[t+e*(n-t),r+e*(a-r)]:void 0}}function f(t,r,n,i,o,u,h,v,f){var M=o+h,c=u+v,d=o+f,s=u+f,I=o+h-f,P=u+v-f,p=[[d,s,Math.PI,1.5*Math.PI],[I,s,1.5*Math.PI,2*Math.PI],[I,P,0,.5*Math.PI],[d,P,.5*Math.PI,Math.PI]],l=[];return[[o,P,o,s,o,u],[d,u,I,u,M,u],[M,s,M,P,M,c],[I,c,d,c,o,c]].forEach((function(o,u){var h=o[0],v=o[1],M=o[2],c=o[3],d=p[u],s=d[0],I=d[1],P=d[2],x=d[3];(function(t,r,n,a,i,o,u){var h,v,e,f,M,c,d,s,I=[o-a,u-i],P=[a-t,i-r];return h=I[0]*P[0]+I[1]*P[1],v=2*(I[0]*I[0]+I[1]*I[1]),h*=-2,e=Math.sqrt(h*h-2*v*(P[0]*P[0]+P[1]*P[1]-n*n)),isNaN(e)?[]:(M=(h+e)/v,d=[],s=[],c=[],(f=(h-e)/v)<=1&&f>=0&&(d[0]=a+I[0]*f,d[1]=i+I[1]*f,c[0]=d),M<=1&&M>=0&&(s[0]=a+I[0]*M,s[1]=i+I[1]*M,c[c.length]=s),c)})(s,I,f,t,r,n,i).filter((function(t){var r,n=(r=a(s,I,t[0],t[1]))-2*Math.PI*Math.floor(r/(2*Math.PI));return n>P&&n<x})).forEach((function(t){return l.push(t)}));var g=e(t,r,n,i,h,v,M,c);g&&l.push(g)})),l}function M(t,r,n,a,i,o,u,h){for(var v=[],e=0,f=[[i,o,i+u,o],[i+u,o,i+u,o+h],[i+u,o+h,i,o+h],[i,o+h,i,o]];e<f.length;e++){var M=f[e],d=c(t,r,n,a,M[0],M[1],M[2],M[3]);d&&v.push(d)}return v}function c(t,r,n,a,i,o,u,h){var v,e,f;if(a*(u-i)!=n*(h-o)&&0!=(f=n*(h-o)-a*(u-i))&&(e=((r-o)*n-(t-i)*a)/f,(v=((r-o)*(u-i)-(t-i)*(h-o))/f)>=0&&e>=0&&e<=1))return[t+v*n,r+v*a]}Object.defineProperty(exports,"__esModule",{value:!0}),exports.getArrow=function(v,e,f,M,c){void 0===c&&(c={});var d=c.bow,s=void 0===d?0:d,I=c.stretch,P=void 0===I?.5:I,p=c.stretchMin,l=void 0===p?0:p,x=c.stretchMax,g=void 0===x?420:x,m=c.padStart,b=void 0===m?0:m,w=c.padEnd,y=void 0===w?0:w,E=c.flip,A=void 0!==E&&E,B=c.straights,N=void 0===B||B,S=a(v,e,f,M),_=n(v,e,f,M),j=h(v,e,f,M);if(_<2*(b+y)||0===s&&0===P||N&&[0,1,Infinity].includes(j)){var q=Math.max(0,Math.min(_-b,b)),O=Math.max(0,Math.min(_-q,y)),T=i(v,e,S,q),k=T[0],z=T[1],C=i(f,M,S+Math.PI,O),D=C[0],F=C[1],G=o(k,z,D,F,.5);return[k,z,G[0],G[1],D,F,S,S,S]}var H=(u(S)%2==0?1:-1)*(A?-1:1),J=s+t(_,[l,g],[1,0],!0)*P,K=o(v,e,f,M,.5),L=K[0],Q=K[1],R=o(v,e,f,M,.5-J),U=R[0],V=R[1],W=r(U,V,L,Q,Math.PI/2*H),X=i(v,e,a(v,e,U=W[0],V=W[1]),b),Y=X[0],Z=X[1],$=i(f,M,a(f,M,U,V),y),tt=$[0],rt=$[1],nt=a(U,V,v,e),at=a(U,V,f,M),it=o(Y,Z,tt,rt,.5),ot=it[0],ut=it[1],ht=o(Y,Z,tt,rt,.5-J),vt=ht[0],et=ht[1],ft=r(vt,et,ot,ut,Math.PI/2*H),Mt=o(U,V,vt=ft[0],et=ft[1],.5);return[Y,Z,Mt[0],Mt[1],tt,rt,at,nt,S]},exports.getBoxToBoxArrow=function(e,c,d,s,I,P,p,l,x){var g,m,b,w;void 0===x&&(x={});var y=x.bow,E=void 0===y?0:y,A=x.stretch,B=void 0===A?.5:A,N=x.stretchMin,S=void 0===N?0:N,_=x.stretchMax,j=void 0===_?420:_,q=x.padStart,O=void 0===q?20:q,T=x.padEnd,k=void 0===T?20:T,z=x.flip,C=void 0!==z&&z,D=x.straights,F=void 0===D||D,G=e+d/2,H=c+s/2,J=I+p/2,K=P+l/2,L=e-O,Q=c-O,R=d+2*O,U=s+2*O,V=I-k,W=P-k,X=p+2*k,Y=l+2*k,Z=o(G,H,J,K,.5),$=Z[0],tt=Z[1],rt=a(G,H,J,K),nt=h(G,H,J,K),at=2*Math.min(R,U,X,Y),it=n(e,c,I,P),ot=at-it,ut=function(t,r,n,a,i,o,u,h){return!(t>=i+u||i>=t+n||r>=o+h||o>=r+a)}(L,Q,R,U,V,W,X,Y);if(F&&([0,1,Infinity].includes(nt)||G===J||H===K)&&!ut){var ht=v(G,H,J,K,L,Q,R,U)[0];g=ht[0],m=ht[1];var vt=v(G,H,J,K,V,W,X,Y)[0];return[g,m,$,tt,b=vt[0],w=vt[1],rt,rt+Math.PI,rt]}var et=(u(rt)%2==0?1:-1)*(C?-1:1),ft=t(it,[S,j],[1,0],!0),Mt=E+ft*B/2,ct=o(G,H,J,K,.5-Mt),dt=ct[0],st=ct[1],It=r(dt,st,$,tt,Math.PI/2*et);if(dt=It[0],st=It[1],ot>0){var Pt=i(dt,st,rt+Math.PI/2*-et,ot*Mt);dt=Pt[0],st=Pt[1]}var pt=f(G,H,dt,st,L,Q,R,U,O),lt=f(J,K,dt,st,V,W,X,Y,k);if(!pt[0]||!lt[0]||n(pt[0][0],pt[0][1],lt[0][0],lt[0][1])<O+k){var xt=function(t){return[Math.cos(t),Math.sin(t)]}(rt+Math.PI),gt=xt[0],mt=xt[1],bt=M(G,H,gt,mt,L,Q,R,U)[0];g=bt[0],m=bt[1];var wt=M(J,K,gt,mt,V,W,X,Y)[0];b=wt[0],w=wt[1],Mt=-1*(E+ft*B)}else{var yt=pt[0];g=yt[0],m=yt[1];var Et=lt[0];b=Et[0],w=Et[1],Mt=E+ft*B}var At=o(g,m,b,w,.5),Bt=At[0],Nt=At[1],St=o(g,m,b,w,.5-Mt),_t=r(dt=St[0],st=St[1],Bt,Nt,Math.PI/(2*et)),jt=a(dt=_t[0],st=_t[1],g,m);return[g,m,dt,st,b,w,a(dt,st,b,w),jt,rt]};
//# sourceMappingURL=perfect-arrows.cjs.production.min.js.map
/**
* Modulate a value between two ranges
* Modulate a value between two ranges.
* @param value

@@ -28,7 +28,7 @@ * @param a from [low, high]

* Rotate a point around a center.
* @param x
* @param y
* @param cx
* @param cy
* @param angle
* @param x The x-axis coordinate of the point.
* @param y The y-axis coordinate of the point.
* @param cx The x-axis coordinate of the point to rotate round.
* @param cy The y-axis coordinate of the point to rotate round.
* @param angle The distance (in radians) to rotate.
*/

@@ -47,6 +47,6 @@

* Get the distance between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -59,6 +59,6 @@

* Get an angle (radians) between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -82,6 +82,6 @@

* Get a point between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
* @param d Normalized

@@ -99,4 +99,4 @@ */

* Get the sector of an angle (e.g. quadrant, octant)
* @param a angle
* @param s number of sectors
* @param a The angle to check.
* @param s The number of sectors to check.
*/

@@ -113,2 +113,207 @@

* Get a normal value representing how close two points are from being at a 45 degree angle.
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/
function getAngliness(x0, y0, x1, y1) {
return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2));
}
/**
* Check whether two rectangles will collide (overlap).
* @param x0 The x-axis coordinate of the first rectangle.
* @param y0 The y-axis coordinate of the first rectangle.
* @param w0 The width of the first rectangle.
* @param h0 The height of the first rectangle.
* @param x1 The x-axis coordinate of the second rectangle.
* @param y1 The y-axis coordinate of the second rectangle.
* @param w1 The width of the second rectangle.
* @param h1 The height of the second rectangle.
*/
function doRectanglesCollide(x0, y0, w0, h0, x1, y1, w1, h1) {
return !(x0 >= x1 + w1 || x1 >= x0 + w0 || y0 >= y1 + h1 || y1 >= y0 + h0);
}
/**
* Find the point(s) where a segment intersects a rectangle.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of the segment's starting point.
* @param x1 The x-axis coordinate of the segment's ending point.
* @param y1 The y-axis coordinate of the segment's ending point.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
*/
function getSegmentRectangleIntersectionPoints(x0, y0, x1, y1, x, y, w, h) {
var points = [];
for (var _i2 = 0, _arr2 = [[x, y, x + w, y], [x + w, y, x + w, y + h], [x + w, y + h, x, y + h], [x, y + h, x, y]]; _i2 < _arr2.length; _i2++) {
var _arr2$_i = _arr2[_i2],
px0 = _arr2$_i[0],
py0 = _arr2$_i[1],
px1 = _arr2$_i[2],
py1 = _arr2$_i[3];
var ints = getSegmentSegmentIntersection(px0, py0, px1, py1, x0, y0, x1, y1);
if (ints) {
points.push(ints);
}
}
return points;
}
/**
* Find the point, if any, where two segments intersect.
* @param x0 The x-axis coordinate of the first segment's starting point.
* @param y0 The y-axis coordinate of the first segment's starting point.
* @param x1 The x-axis coordinate of the first segment's ending point.
* @param y1 The y-axis coordinate of the first segment's ending point.
* @param x2 The x-axis coordinate of the second segment's starting point.
* @param y2 The y-axis coordinate of the second segment's starting point.
* @param x3 The x-axis coordinate of the second segment's ending point.
* @param y3 The y-axis coordinate of the second segment's ending point.
*/
function getSegmentSegmentIntersection(x0, y0, x1, y1, x2, y2, x3, y3) {
var denom = (y3 - y2) * (x1 - x0) - (x3 - x2) * (y1 - y0);
var numeA = (x3 - x2) * (y0 - y2) - (y3 - y2) * (x0 - x2);
var numeB = (x1 - x0) * (y0 - y2) - (y1 - y0) * (x0 - x2);
if (denom === 0) {
if (numeA === 0 && numeB === 0) {
return undefined; // Colinear
}
return undefined; // Parallel
}
var uA = numeA / denom;
var uB = numeB / denom;
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
return [x0 + uA * (x1 - x0), y0 + uA * (y1 - y0)];
}
return undefined; // No intersection
}
/**
* Get the intersection points between a line segment and a rectangle with rounded corners.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
* @param r The corner radius of the rectangle.
*/
function getSegmentRoundedRectangleIntersectionPoints(x0, y0, x1, y1, x, y, w, h, r) {
var mx = x + w,
my = y + h,
rx = x + r,
ry = y + r,
mrx = x + w - r,
mry = y + h - r;
var segments = [[x, mry, x, ry, x, y], [rx, y, mrx, y, mx, y], [mx, ry, mx, mry, mx, my], [mrx, my, rx, my, x, my]];
var corners = [[rx, ry, Math.PI, Math.PI * 1.5], [mrx, ry, Math.PI * 1.5, Math.PI * 2], [mrx, mry, 0, Math.PI * 0.5], [rx, mry, Math.PI * 0.5, Math.PI]];
var points = [];
segments.forEach(function (segment, i) {
var px0 = segment[0],
py0 = segment[1],
px1 = segment[2],
py1 = segment[3];
var _corners$i = corners[i],
cx = _corners$i[0],
cy = _corners$i[1],
as = _corners$i[2],
ae = _corners$i[3];
getSegmentCircleIntersections(cx, cy, r, x0, y0, x1, y1).filter(function (pt) {
var pointAngle = normalizeAngle(getAngle(cx, cy, pt[0], pt[1]));
return pointAngle > as && pointAngle < ae;
}).forEach(function (pt) {
return points.push(pt);
});
var segmentInt = getSegmentSegmentIntersection(x0, y0, x1, y1, px0, py0, px1, py1);
if (!!segmentInt) {
points.push(segmentInt);
}
});
return points;
}
/**
* Get the point(s) where a line segment intersects a circle.
* @param cx The x-axis coordinate of the circle's center.
* @param cy The y-axis coordinate of the circle's center.
* @param r The circle's radius.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
*/
function getSegmentCircleIntersections(cx, cy, r, x0, y0, x1, y1) {
var b,
c,
d,
u1,
u2,
ret,
retP1,
retP2,
v1 = [x1 - x0, y1 - y0],
v2 = [x0 - cx, y0 - cy];
b = v1[0] * v2[0] + v1[1] * v2[1];
c = 2 * (v1[0] * v1[0] + v1[1] * v1[1]);
b *= -2;
d = Math.sqrt(b * b - 2 * c * (v2[0] * v2[0] + v2[1] * v2[1] - r * r));
if (isNaN(d)) {
// no intercept
return [];
}
u1 = (b - d) / c; // these represent the unit distance of point one and two on the line
u2 = (b + d) / c;
retP1 = []; // return points
retP2 = [];
ret = []; // return array
if (u1 <= 1 && u1 >= 0) {
// add point if on the line segment
retP1[0] = x0 + v1[0] * u1;
retP1[1] = y0 + v1[1] * u1;
ret[0] = retP1;
}
if (u2 <= 1 && u2 >= 0) {
// second add point if on the line segment
retP2[0] = x0 + v1[0] * u2;
retP2[1] = y0 + v1[1] * u2;
ret[ret.length] = retP2;
}
return ret;
}
/**
* Normalize an angle (in radians)
* @param radians The radians quantity to normalize.
*/
function normalizeAngle(radians) {
return radians - Math.PI * 2 * Math.floor(radians / (Math.PI * 2));
}
/**
*
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param w
* @param h
* @param x0

@@ -120,8 +325,62 @@ * @param y0

function getAngliness(x0, y0, x1, y1) {
return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2));
function getRayRectangleIntersectionPoints(ox, oy, dx, dy, x, y, w, h) {
var points = [];
for (var _i3 = 0, _arr3 = [[x, y, x + w, y], [x + w, y, x + w, y + h], [x + w, y + h, x, y + h], [x, y + h, x, y]]; _i3 < _arr3.length; _i3++) {
var _arr3$_i = _arr3[_i3],
px0 = _arr3$_i[0],
py0 = _arr3$_i[1],
px1 = _arr3$_i[2],
py1 = _arr3$_i[3];
var ints = getRaySegmentIntersection(ox, oy, dx, dy, px0, py0, px1, py1);
if (ints) {
points.push(ints);
}
}
return points;
}
/**
* Get the point at which a ray intersects a segment.
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param dx The x-axis delta of the angle.
* @param dy The y-axis delta of the angle.
* @param x0 The x-axis coordinate of the segment's start point.
* @param y0 The y-axis coordinate of the segment's start point.
* @param x1 The x-axis coordinate of the segment's end point.
* @param y1 The y-axis coordinate of the segment's end point.
*/
function getRaySegmentIntersection(x, y, dx, dy, x0, y0, x1, y1) {
var r, s, d;
if (dy * (x1 - x0) !== dx * (y1 - y0)) {
d = dx * (y1 - y0) - dy * (x1 - x0);
if (d !== 0) {
r = ((y - y0) * (x1 - x0) - (x - x0) * (y1 - y0)) / d;
s = ((y - y0) * dx - (x - x0) * dy) / d;
if (r >= 0 && s >= 0 && s <= 1) {
return [x + r * dx, y + r * dy];
}
}
}
return undefined;
}
/**
* Get the normalized delta (x and y) for an angle.
* @param angle The angle in radians
*/
function getDelta(angle) {
return [Math.cos(angle), Math.sin(angle)];
}
/**
* getArrow
* Get the points for a linking line between two points.
* @description Draw an arrow between two points.

@@ -271,3 +530,160 @@ * @param x0 The x position of the "from" point.

export { getArrow };
/**
* getArrowBetweenBoxes
* Get the points for a linking line between two boxes.
* @param x0 The x-axis coordinate of the first box.
* @param y0 The y-axis coordinate of the first box.
* @param w0 The width of the first box.
* @param h0 The height of the first box.
* @param x1 The x-axis coordinate of the second box.
* @param y1 The y-axis coordinate of the second box.
* @param w1 The width of the second box.
* @param h1 The height of the second box.
* @param options
*/
function getBoxToBoxArrow(x0, y0, w0, h0, x1, y1, w1, h1, options) {
if (options === void 0) {
options = {};
}
var i0x, i0y, i1x, i1y;
var _options = options,
_options$bow = _options.bow,
bow = _options$bow === void 0 ? 0 : _options$bow,
_options$stretch = _options.stretch,
stretch = _options$stretch === void 0 ? 0.5 : _options$stretch,
_options$stretchMin = _options.stretchMin,
stretchMin = _options$stretchMin === void 0 ? 0 : _options$stretchMin,
_options$stretchMax = _options.stretchMax,
stretchMax = _options$stretchMax === void 0 ? 420 : _options$stretchMax,
_options$padStart = _options.padStart,
padStart = _options$padStart === void 0 ? 20 : _options$padStart,
_options$padEnd = _options.padEnd,
padEnd = _options$padEnd === void 0 ? 20 : _options$padEnd,
_options$flip = _options.flip,
flip = _options$flip === void 0 ? false : _options$flip,
_options$straights = _options.straights,
straights = _options$straights === void 0 ? true : _options$straights;
var cx0 = x0 + w0 / 2,
cy0 = y0 + h0 / 2,
cx1 = x1 + w1 / 2,
cy1 = y1 + h1 / 2,
px0 = x0 - padStart,
py0 = y0 - padStart,
pw0 = w0 + padStart * 2,
ph0 = h0 + padStart * 2,
px1 = x1 - padEnd,
py1 = y1 - padEnd,
pw1 = w1 + padEnd * 2,
ph1 = h1 + padEnd * 2;
var _getPointBetween = getPointBetween(cx0, cy0, cx1, cy1, 0.5),
mx = _getPointBetween[0],
my = _getPointBetween[1];
var angle = getAngle(cx0, cy0, cx1, cy1);
var angliness = getAngliness(cx0, cy0, cx1, cy1);
var minLength = Math.min(pw0, ph0, pw1, ph1) * 2;
var direct = getDistance(x0, y0, x1, y1);
var overflow = minLength - direct;
var isColliding = doRectanglesCollide(px0, py0, pw0, ph0, px1, py1, pw1, ph1);
if (straights && ([0, 1, Infinity].includes(angliness) || cx0 === cx1 || cy0 === cy1) && !isColliding) {
var _getSegmentRectangleI = getSegmentRectangleIntersectionPoints(cx0, cy0, cx1, cy1, px0, py0, pw0, ph0);
var _getSegmentRectangleI2 = _getSegmentRectangleI[0];
i0x = _getSegmentRectangleI2[0];
i0y = _getSegmentRectangleI2[1];
var _getSegmentRectangleI3 = getSegmentRectangleIntersectionPoints(cx0, cy0, cx1, cy1, px1, py1, pw1, ph1);
var _getSegmentRectangleI4 = _getSegmentRectangleI3[0];
i1x = _getSegmentRectangleI4[0];
i1y = _getSegmentRectangleI4[1];
return [i0x, i0y, mx, my, i1x, i1y, angle, angle + Math.PI, angle];
} // ⤜⤏ Arrow is an arc!
// Is the arc clockwise or counterclockwise?
var rot = (getSector(angle) % 2 === 0 ? 1 : -1) * (flip ? -1 : 1); // Calculate how much the line should "bow" away from center
var stretchEffect = mod(direct, [stretchMin, stretchMax], [1, 0], true);
var arc = bow + stretchEffect * stretch / 2; // Step 1 ⤜⤏ Find padded points.
// Get control point.
var _getPointBetween2 = getPointBetween(cx0, cy0, cx1, cy1, 0.5 - arc),
cx = _getPointBetween2[0],
cy = _getPointBetween2[1];
var _rotatePoint = rotatePoint(cx, cy, mx, my, Math.PI / 2 * rot);
cx = _rotatePoint[0];
cy = _rotatePoint[1];
if (overflow > 0) {
var _projectPoint = projectPoint(cx, cy, angle + Math.PI / 2 * -rot, overflow * arc);
cx = _projectPoint[0];
cy = _projectPoint[1];
} // Get padded start point.
var i0 = getSegmentRoundedRectangleIntersectionPoints(cx0, cy0, cx, cy, px0, py0, pw0, ph0, padStart); // Get padded end point.
var i1 = getSegmentRoundedRectangleIntersectionPoints(cx1, cy1, cx, cy, px1, py1, pw1, ph1, padEnd); // If we don't have intersections, or if the distance between the
// intersections is very small, use the backup point-finding stategy
if (!(i0[0] && i1[0]) || getDistance(i0[0][0], i0[0][1], i1[0][0], i1[0][1]) < padStart + padEnd) {
// Basically, shoot a ray based on the opposite angle between
// the two centers, and see where it intersects the rectangles.
// This part can definitely be improved!
var _getDelta = getDelta(angle + Math.PI),
dx = _getDelta[0],
dy = _getDelta[1];
var _getRayRectangleInter = getRayRectangleIntersectionPoints(cx0, cy0, dx, dy, px0, py0, pw0, ph0);
var _getRayRectangleInter2 = _getRayRectangleInter[0];
i0x = _getRayRectangleInter2[0];
i0y = _getRayRectangleInter2[1];
var _getRayRectangleInter3 = getRayRectangleIntersectionPoints(cx1, cy1, dx, dy, px1, py1, pw1, ph1);
var _getRayRectangleInter4 = _getRayRectangleInter3[0];
i1x = _getRayRectangleInter4[0];
i1y = _getRayRectangleInter4[1];
arc = (bow + stretchEffect * stretch) * -1;
} else {
var _i0$ = i0[0];
i0x = _i0$[0];
i0y = _i0$[1];
var _i1$ = i1[0];
i1x = _i1$[0];
i1y = _i1$[1];
arc = bow + stretchEffect * stretch;
} // Step 3 ⤜⤏ Calculate arrow points using same algorithm as getArrow
var _getPointBetween3 = getPointBetween(i0x, i0y, i1x, i1y, 0.5),
mx1 = _getPointBetween3[0],
my1 = _getPointBetween3[1];
var _getPointBetween4 = getPointBetween(i0x, i0y, i1x, i1y, 0.5 - arc);
cx = _getPointBetween4[0];
cy = _getPointBetween4[1];
var _rotatePoint2 = rotatePoint(cx, cy, mx1, my1, Math.PI / (2 * rot));
cx = _rotatePoint2[0];
cy = _rotatePoint2[1];
var as = getAngle(cx, cy, i0x, i0y);
var ae = getAngle(cx, cy, i1x, i1y);
return [i0x, i0y, cx, cy, i1x, i1y, ae, as, angle];
}
export { getArrow, getBoxToBoxArrow };
//# sourceMappingURL=perfect-arrows.esm.js.map
{
"version": "0.2.0",
"version": "0.2.1",
"license": "MIT",

@@ -4,0 +4,0 @@ "main": "dist/index.js",

@@ -1,3 +0,3 @@

import { getArrow, ArrowOptions } from "./lib"
import { getArrow, getBoxToBoxArrow, ArrowOptions } from "./lib"
export { getArrow, ArrowOptions }
export { getArrow, getBoxToBoxArrow, ArrowOptions }

@@ -25,2 +25,3 @@ import {

* getArrow
* Get the points for a linking line between two points.
* @description Draw an arrow between two points.

@@ -27,0 +28,0 @@ * @param x0 The x position of the "from" point.

import getArrow, { ArrowOptions } from "./getArrow"
import getBoxToBoxArrow from "./getBoxToBoxArrow"
export { getArrow, ArrowOptions }
export { getArrow, ArrowOptions, getBoxToBoxArrow }
/**
* Modulate a value between two ranges
* Modulate a value between two ranges.
* @param value

@@ -22,7 +22,7 @@ * @param a from [low, high]

* Rotate a point around a center.
* @param x
* @param y
* @param cx
* @param cy
* @param angle
* @param x The x-axis coordinate of the point.
* @param y The y-axis coordinate of the point.
* @param cx The x-axis coordinate of the point to rotate round.
* @param cy The y-axis coordinate of the point to rotate round.
* @param angle The distance (in radians) to rotate.
*/

@@ -50,6 +50,6 @@ export function rotatePoint(

* Get the distance between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -62,6 +62,6 @@ export function getDistance(x0: number, y0: number, x1: number, y1: number) {

* Get an angle (radians) between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/

@@ -85,6 +85,6 @@ export function getAngle(x0: number, y0: number, x1: number, y1: number) {

* Get a point between two points.
* @param x0
* @param y0
* @param x1
* @param y1
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
* @param d Normalized

@@ -104,4 +104,4 @@ */

* Get the sector of an angle (e.g. quadrant, octant)
* @param a angle
* @param s number of sectors
* @param a The angle to check.
* @param s The number of sectors to check.
*/

@@ -114,2 +114,411 @@ export function getSector(a: number, s = 8) {

* Get a normal value representing how close two points are from being at a 45 degree angle.
* @param x0 The x-axis coordinate of the first point.
* @param y0 The y-axis coordinate of the first point.
* @param x1 The x-axis coordinate of the second point.
* @param y1 The y-axis coordinate of the second point.
*/
export function getAngliness(x0: number, y0: number, x1: number, y1: number) {
return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2))
}
/**
* Get the points at which an ellipse intersects a rectangle.
* @param x
* @param y
* @param w
* @param h
* @param cx
* @param cy
* @param rx
* @param ry
* @param angle
*/
export function getEllipseRectangleIntersectionPoints(
x: number,
y: number,
w: number,
h: number,
cx: number,
cy: number,
rx: number,
ry: number,
angle: number
) {
let points: number[][] = []
for (let [px0, py0, px1, py1] of [
[x, y, x + w, y],
[x + w, y, x + w, y + h],
[x + w, y + h, x, y + h],
[x, y + h, x, y],
]) {
const ints = getEllipseSegmentIntersections(
px0,
py0,
px1,
py1,
cx,
cy,
rx,
ry,
angle
)
if (ints.length > 0) {
points.push(...ints)
}
}
points = points.sort(([x0, y0], [x1, y1]) => {
return Math.sin(getAngle(cx, cy, x0, y0) - getAngle(cx, cy, x1, y1)) > 0
? -1
: 1
})
return points
}
/**
* Find the point(s) where a line segment intersects an ellipse.
* @param x0 The x-axis coordinate of the line's start point.
* @param y0 The y-axis coordinate of the line's start point.
* @param x1 The x-axis coordinate of the line's end point.
* @param y1 The y-axis coordinate of the line's end point.
* @param cx The x-axis (horizontal) coordinate of the ellipse's center.
* @param cy The y-axis (vertical) coordinate of the ellipse's center.
* @param rx The ellipse's major-axis radius. Must be non-negative.
* @param ry The ellipse's minor-axis radius. Must be non-negative.
* @param rotation The rotation of the ellipse, expressed in radians.
* @param segment_only When true, will test the segment as a line (of infinite length).
*/
export function getEllipseSegmentIntersections(
x0: number,
y0: number,
x1: number,
y1: number,
cx: number,
cy: number,
rx: number,
ry: number,
rotation = 0,
segment_only = true
) {
// If the ellipse or line segment are empty, return no tValues.
if (rx === 0 || ry === 0 || (x0 === x1 && y0 === y1)) {
return []
}
// Get the semimajor and semiminor axes.
rx = rx < 0 ? rx : -rx
ry = ry < 0 ? ry : -ry
// Rotate points.
if (rotation !== 0) {
;[x0, y0] = rotatePoint(x0, y0, cx, cy, -rotation)
;[x1, y1] = rotatePoint(x1, y1, cx, cy, -rotation)
}
// Translate so the ellipse is centered at the origin.
x0 -= cx
y0 -= cy
x1 -= cx
y1 -= cy
// Calculate the quadratic parameters.
var A = ((x1 - x0) * (x1 - x0)) / rx / rx + ((y1 - y0) * (y1 - y0)) / ry / ry
var B = (2 * x0 * (x1 - x0)) / rx / rx + (2 * y0 * (y1 - y0)) / ry / ry
var C = (x0 * x0) / rx / rx + (y0 * y0) / ry / ry - 1
// Make a list of t values (normalized points on the line where intersections occur).
var tValues: number[] = []
// Calculate the discriminant.
var discriminant = B * B - 4 * A * C
if (discriminant === 0) {
// One real solution.
tValues.push(-B / 2 / A)
} else if (discriminant > 0) {
// Two real solutions.
tValues.push((-B + Math.sqrt(discriminant)) / 2 / A)
tValues.push((-B - Math.sqrt(discriminant)) / 2 / A)
}
return (
tValues
// Filter to only points that are on the segment.
.filter(t => !segment_only || (t >= 0 && t <= 1))
// Solve for points.
.map(t => [x0 + (x1 - x0) * t + cx, y0 + (y1 - y0) * t + cy])
// Counter-rotate points
.map(p =>
rotation === 0 ? p : rotatePoint(p[0], p[1], cx, cy, rotation)
)
)
}
/**
* Check whether two rectangles will collide (overlap).
* @param x0 The x-axis coordinate of the first rectangle.
* @param y0 The y-axis coordinate of the first rectangle.
* @param w0 The width of the first rectangle.
* @param h0 The height of the first rectangle.
* @param x1 The x-axis coordinate of the second rectangle.
* @param y1 The y-axis coordinate of the second rectangle.
* @param w1 The width of the second rectangle.
* @param h1 The height of the second rectangle.
*/
export function doRectanglesCollide(
x0: number,
y0: number,
w0: number,
h0: number,
x1: number,
y1: number,
w1: number,
h1: number
) {
return !(x0 >= x1 + w1 || x1 >= x0 + w0 || y0 >= y1 + h1 || y1 >= y0 + h0)
}
/**
* Find the point(s) where a segment intersects a rectangle.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of the segment's starting point.
* @param x1 The x-axis coordinate of the segment's ending point.
* @param y1 The y-axis coordinate of the segment's ending point.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
*/
export function getSegmentRectangleIntersectionPoints(
x0: number,
y0: number,
x1: number,
y1: number,
x: number,
y: number,
w: number,
h: number
) {
let points: number[][] = []
for (let [px0, py0, px1, py1] of [
[x, y, x + w, y],
[x + w, y, x + w, y + h],
[x + w, y + h, x, y + h],
[x, y + h, x, y],
]) {
const ints = getSegmentSegmentIntersection(
px0,
py0,
px1,
py1,
x0,
y0,
x1,
y1
)
if (ints) {
points.push(ints)
}
}
return points
}
/**
* Find the point, if any, where two segments intersect.
* @param x0 The x-axis coordinate of the first segment's starting point.
* @param y0 The y-axis coordinate of the first segment's starting point.
* @param x1 The x-axis coordinate of the first segment's ending point.
* @param y1 The y-axis coordinate of the first segment's ending point.
* @param x2 The x-axis coordinate of the second segment's starting point.
* @param y2 The y-axis coordinate of the second segment's starting point.
* @param x3 The x-axis coordinate of the second segment's ending point.
* @param y3 The y-axis coordinate of the second segment's ending point.
*/
export function getSegmentSegmentIntersection(
x0: number,
y0: number,
x1: number,
y1: number,
x2: number,
y2: number,
x3: number,
y3: number
) {
const denom = (y3 - y2) * (x1 - x0) - (x3 - x2) * (y1 - y0)
const numeA = (x3 - x2) * (y0 - y2) - (y3 - y2) * (x0 - x2)
const numeB = (x1 - x0) * (y0 - y2) - (y1 - y0) * (x0 - x2)
if (denom === 0) {
if (numeA === 0 && numeB === 0) {
return undefined // Colinear
}
return undefined // Parallel
}
const uA = numeA / denom
const uB = numeB / denom
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
return [x0 + uA * (x1 - x0), y0 + uA * (y1 - y0)]
}
return undefined // No intersection
}
/**
* Get the intersection points between a line segment and a rectangle with rounded corners.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
* @param x The x-axis coordinate of the rectangle.
* @param y The y-axis coordinate of the rectangle.
* @param w The width of the rectangle.
* @param h The height of the rectangle.
* @param r The corner radius of the rectangle.
*/
export function getSegmentRoundedRectangleIntersectionPoints(
x0: number,
y0: number,
x1: number,
y1: number,
x: number,
y: number,
w: number,
h: number,
r: number
) {
const mx = x + w,
my = y + h,
rx = x + r,
ry = y + r,
mrx = x + w - r,
mry = y + h - r
const segments = [
[x, mry, x, ry, x, y],
[rx, y, mrx, y, mx, y],
[mx, ry, mx, mry, mx, my],
[mrx, my, rx, my, x, my],
]
const corners = [
[rx, ry, Math.PI, Math.PI * 1.5],
[mrx, ry, Math.PI * 1.5, Math.PI * 2],
[mrx, mry, 0, Math.PI * 0.5],
[rx, mry, Math.PI * 0.5, Math.PI],
]
let points: number[][] = []
segments.forEach((segment, i) => {
const [px0, py0, px1, py1] = segment
const [cx, cy, as, ae] = corners[i]
getSegmentCircleIntersections(cx, cy, r, x0, y0, x1, y1)
.filter(pt => {
const pointAngle = normalizeAngle(getAngle(cx, cy, pt[0], pt[1]))
return pointAngle > as && pointAngle < ae
})
.forEach(pt => points.push(pt))
const segmentInt = getSegmentSegmentIntersection(
x0,
y0,
x1,
y1,
px0,
py0,
px1,
py1
)
if (!!segmentInt) {
points.push(segmentInt)
}
})
return points
}
/**
* Get the point(s) where a line segment intersects a circle.
* @param cx The x-axis coordinate of the circle's center.
* @param cy The y-axis coordinate of the circle's center.
* @param r The circle's radius.
* @param x0 The x-axis coordinate of the segment's starting point.
* @param y0 The y-axis coordinate of ththe segment's ending point.
* @param x1 The delta-x of the ray.
* @param y1 The delta-y of the ray.
*/
export function getSegmentCircleIntersections(
cx: number,
cy: number,
r: number,
x0: number,
y0: number,
x1: number,
y1: number
) {
var b: number,
c: number,
d: number,
u1: number,
u2: number,
ret: number[][],
retP1: number[],
retP2: number[],
v1 = [x1 - x0, y1 - y0],
v2 = [x0 - cx, y0 - cy]
b = v1[0] * v2[0] + v1[1] * v2[1]
c = 2 * (v1[0] * v1[0] + v1[1] * v1[1])
b *= -2
d = Math.sqrt(b * b - 2 * c * (v2[0] * v2[0] + v2[1] * v2[1] - r * r))
if (isNaN(d)) {
// no intercept
return []
}
u1 = (b - d) / c // these represent the unit distance of point one and two on the line
u2 = (b + d) / c
retP1 = [] // return points
retP2 = []
ret = [] // return array
if (u1 <= 1 && u1 >= 0) {
// add point if on the line segment
retP1[0] = x0 + v1[0] * u1
retP1[1] = y0 + v1[1] * u1
ret[0] = retP1
}
if (u2 <= 1 && u2 >= 0) {
// second add point if on the line segment
retP2[0] = x0 + v1[0] * u2
retP2[1] = y0 + v1[1] * u2
ret[ret.length] = retP2
}
return ret
}
/**
* Normalize an angle (in radians)
* @param radians The radians quantity to normalize.
*/
export function normalizeAngle(radians: number) {
return radians - Math.PI * 2 * Math.floor(radians / (Math.PI * 2))
}
/**
*
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param w
* @param h
* @param x0

@@ -120,4 +529,71 @@ * @param y0

*/
export function getAngliness(x0: number, y0: number, x1: number, y1: number) {
return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2))
export function getRayRectangleIntersectionPoints(
ox: number,
oy: number,
dx: number,
dy: number,
x: number,
y: number,
w: number,
h: number
) {
let points: number[][] = []
for (let [px0, py0, px1, py1] of [
[x, y, x + w, y],
[x + w, y, x + w, y + h],
[x + w, y + h, x, y + h],
[x, y + h, x, y],
]) {
const ints = getRaySegmentIntersection(ox, oy, dx, dy, px0, py0, px1, py1)
if (ints) {
points.push(ints)
}
}
return points
}
/**
* Get the point at which a ray intersects a segment.
* @param x The x-axis coordinate of the ray's origin.
* @param y The y-axis coordinate of the ray's origin.
* @param dx The x-axis delta of the angle.
* @param dy The y-axis delta of the angle.
* @param x0 The x-axis coordinate of the segment's start point.
* @param y0 The y-axis coordinate of the segment's start point.
* @param x1 The x-axis coordinate of the segment's end point.
* @param y1 The y-axis coordinate of the segment's end point.
*/
export function getRaySegmentIntersection(
x: number,
y: number,
dx: number,
dy: number,
x0: number,
y0: number,
x1: number,
y1: number
) {
let r: number, s: number, d: number
if (dy * (x1 - x0) !== dx * (y1 - y0)) {
d = dx * (y1 - y0) - dy * (x1 - x0)
if (d !== 0) {
r = ((y - y0) * (x1 - x0) - (x - x0) * (y1 - y0)) / d
s = ((y - y0) * dx - (x - x0) * dy) / d
if (r >= 0 && s >= 0 && s <= 1) {
return [x + r * dx, y + r * dy]
}
}
}
return undefined
}
/**
* Get the normalized delta (x and y) for an angle.
* @param angle The angle in radians
*/
export function getDelta(angle: number) {
return [Math.cos(angle), Math.sin(angle)]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc