123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- import { Point } from "roughjs/bin/geometry";
- // https://stackoverflow.com/a/6853926/232122
- export function distanceBetweenPointAndSegment(
- x: number,
- y: number,
- x1: number,
- y1: number,
- x2: number,
- y2: number,
- ) {
- const A = x - x1;
- const B = y - y1;
- const C = x2 - x1;
- const D = y2 - y1;
- const dot = A * C + B * D;
- const lenSquare = C * C + D * D;
- let param = -1;
- if (lenSquare !== 0) {
- // in case of 0 length line
- param = dot / lenSquare;
- }
- let xx, yy;
- if (param < 0) {
- xx = x1;
- yy = y1;
- } else if (param > 1) {
- xx = x2;
- yy = y2;
- } else {
- xx = x1 + param * C;
- yy = y1 + param * D;
- }
- const dx = x - xx;
- const dy = y - yy;
- return Math.hypot(dx, dy);
- }
- export function rotate(
- x1: number,
- y1: number,
- x2: number,
- y2: number,
- angle: number,
- ) {
- // 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
- // 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
- // https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
- return [
- (x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2,
- (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2,
- ];
- }
- export const getPointOnAPath = (point: Point, path: Point[]) => {
- const [px, py] = point;
- const [start, ...other] = path;
- let [lastX, lastY] = start;
- let kLine: number = 0;
- let idx: number = 0;
- // if any item in the array is true, it means that a point is
- // on some segment of a line based path
- const retVal = other.some(([x2, y2], i) => {
- // we always take a line when dealing with line segments
- const x1 = lastX;
- const y1 = lastY;
- lastX = x2;
- lastY = y2;
- // if a point is not within the domain of the line segment
- // it is not on the line segment
- if (px < x1 || px > x2) {
- return false;
- }
- // check if all points lie on the same line
- // y1 = kx1 + b, y2 = kx2 + b
- // y2 - y1 = k(x2 - x2) -> k = (y2 - y1) / (x2 - x1)
- // coefficient for the line (p0, p1)
- const kL = (y2 - y1) / (x2 - x1);
- // coefficient for the line segment (p0, point)
- const kP1 = (py - y1) / (px - x1);
- // coefficient for the line segment (point, p1)
- const kP2 = (py - y2) / (px - x2);
- // because we are basing both lines from the same starting point
- // the only option for collinearity is having same coefficients
- // using it for floating point comparisons
- const epsilon = 0.3;
- // if coefficient is more than an arbitrary epsilon,
- // these lines are nor collinear
- if (Math.abs(kP1 - kL) > epsilon && Math.abs(kP2 - kL) > epsilon) {
- return false;
- }
- // store the coefficient because we are goint to need it
- kLine = kL;
- idx = i;
- return true;
- });
- // Return a coordinate that is always on the line segment
- if (retVal === true) {
- return { x: point[0], y: kLine * point[0], segment: idx };
- }
- return null;
- };
|