mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-11-04 12:54:23 +01:00 
			
		
		
		
	* new collision api * isPointOnShape * removed redundant code * new collision methods in app * curve shape takes starting point * clean up geometry * curve rotation * freedraw * inside curve * improve ellipse inside check * ellipse distance func * curve inside * include frame name bounds * replace previous private methods for getting elements at x,y * arrow bound text hit detection * keep iframes on top * remove dependence on old collision methods from app * remove old collision functions * move some hit functions outside of app * code refactor * type * text collision from inside * fix context menu test * highest z-index collision * fix 1px away binding test * strictly less * remove unused imports * lint * 'ignore' resize flipping test * more lint fix * skip 'flips while resizing' test * more test * fix merge errors * fix selection in resize test * added a bit more comment --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
		
			
				
	
	
		
			250 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import {
 | 
						|
  lineIntersectsLine,
 | 
						|
  lineRotate,
 | 
						|
  pointInEllipse,
 | 
						|
  pointInPolygon,
 | 
						|
  pointLeftofLine,
 | 
						|
  pointOnCurve,
 | 
						|
  pointOnEllipse,
 | 
						|
  pointOnLine,
 | 
						|
  pointOnPolygon,
 | 
						|
  pointOnPolyline,
 | 
						|
  pointRightofLine,
 | 
						|
  pointRotate,
 | 
						|
} from "./geometry";
 | 
						|
import { Curve, Ellipse, Line, Point, Polygon, Polyline } from "./shape";
 | 
						|
 | 
						|
describe("point and line", () => {
 | 
						|
  const line: Line = [
 | 
						|
    [1, 0],
 | 
						|
    [1, 2],
 | 
						|
  ];
 | 
						|
 | 
						|
  it("point on left or right of line", () => {
 | 
						|
    expect(pointLeftofLine([0, 1], line)).toBe(true);
 | 
						|
    expect(pointLeftofLine([1, 1], line)).toBe(false);
 | 
						|
    expect(pointLeftofLine([2, 1], line)).toBe(false);
 | 
						|
 | 
						|
    expect(pointRightofLine([0, 1], line)).toBe(false);
 | 
						|
    expect(pointRightofLine([1, 1], line)).toBe(false);
 | 
						|
    expect(pointRightofLine([2, 1], line)).toBe(true);
 | 
						|
  });
 | 
						|
 | 
						|
  it("point on the line", () => {
 | 
						|
    expect(pointOnLine([0, 1], line)).toBe(false);
 | 
						|
    expect(pointOnLine([1, 1], line, 0)).toBe(true);
 | 
						|
    expect(pointOnLine([2, 1], line)).toBe(false);
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
describe("point and polylines", () => {
 | 
						|
  const polyline: Polyline = [
 | 
						|
    [
 | 
						|
      [1, 0],
 | 
						|
      [1, 2],
 | 
						|
    ],
 | 
						|
    [
 | 
						|
      [1, 2],
 | 
						|
      [2, 2],
 | 
						|
    ],
 | 
						|
    [
 | 
						|
      [2, 2],
 | 
						|
      [2, 1],
 | 
						|
    ],
 | 
						|
    [
 | 
						|
      [2, 1],
 | 
						|
      [3, 1],
 | 
						|
    ],
 | 
						|
  ];
 | 
						|
 | 
						|
  it("point on the line", () => {
 | 
						|
    expect(pointOnPolyline([1, 0], polyline)).toBe(true);
 | 
						|
    expect(pointOnPolyline([1, 2], polyline)).toBe(true);
 | 
						|
    expect(pointOnPolyline([2, 2], polyline)).toBe(true);
 | 
						|
    expect(pointOnPolyline([2, 1], polyline)).toBe(true);
 | 
						|
    expect(pointOnPolyline([3, 1], polyline)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnPolyline([1, 1], polyline)).toBe(true);
 | 
						|
    expect(pointOnPolyline([2, 1.5], polyline)).toBe(true);
 | 
						|
    expect(pointOnPolyline([2.5, 1], polyline)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnPolyline([0, 1], polyline)).toBe(false);
 | 
						|
    expect(pointOnPolyline([2.1, 1.5], polyline)).toBe(false);
 | 
						|
  });
 | 
						|
 | 
						|
  it("point on the line with rotation", () => {
 | 
						|
    const truePoints = [
 | 
						|
      [1, 0],
 | 
						|
      [1, 2],
 | 
						|
      [2, 2],
 | 
						|
      [2, 1],
 | 
						|
      [3, 1],
 | 
						|
    ] as Point[];
 | 
						|
 | 
						|
    truePoints.forEach((point) => {
 | 
						|
      const rotation = Math.random() * 360;
 | 
						|
      const rotatedPoint = pointRotate(point, rotation);
 | 
						|
      const rotatedPolyline: Polyline = polyline.map((line) =>
 | 
						|
        lineRotate(line, rotation, [0, 0]),
 | 
						|
      );
 | 
						|
      expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(true);
 | 
						|
    });
 | 
						|
 | 
						|
    const falsePoints = [
 | 
						|
      [0, 1],
 | 
						|
      [2.1, 1.5],
 | 
						|
    ] as Point[];
 | 
						|
 | 
						|
    falsePoints.forEach((point) => {
 | 
						|
      const rotation = Math.random() * 360;
 | 
						|
      const rotatedPoint = pointRotate(point, rotation);
 | 
						|
      const rotatedPolyline: Polyline = polyline.map((line) =>
 | 
						|
        lineRotate(line, rotation, [0, 0]),
 | 
						|
      );
 | 
						|
      expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(false);
 | 
						|
    });
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
describe("point and polygon", () => {
 | 
						|
  const polygon: Polygon = [
 | 
						|
    [10, 10],
 | 
						|
    [50, 10],
 | 
						|
    [50, 50],
 | 
						|
    [10, 50],
 | 
						|
  ];
 | 
						|
 | 
						|
  it("point on polygon", () => {
 | 
						|
    expect(pointOnPolygon([30, 10], polygon)).toBe(true);
 | 
						|
    expect(pointOnPolygon([50, 30], polygon)).toBe(true);
 | 
						|
    expect(pointOnPolygon([30, 50], polygon)).toBe(true);
 | 
						|
    expect(pointOnPolygon([10, 30], polygon)).toBe(true);
 | 
						|
    expect(pointOnPolygon([30, 30], polygon)).toBe(false);
 | 
						|
    expect(pointOnPolygon([30, 70], polygon)).toBe(false);
 | 
						|
  });
 | 
						|
 | 
						|
  it("point in polygon", () => {
 | 
						|
    const polygon: Polygon = [
 | 
						|
      [0, 0],
 | 
						|
      [2, 0],
 | 
						|
      [2, 2],
 | 
						|
      [0, 2],
 | 
						|
    ];
 | 
						|
    expect(pointInPolygon([1, 1], polygon)).toBe(true);
 | 
						|
    expect(pointInPolygon([3, 3], polygon)).toBe(false);
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
describe("point and curve", () => {
 | 
						|
  const curve: Curve = [
 | 
						|
    [1.4, 1.65],
 | 
						|
    [1.9, 7.9],
 | 
						|
    [5.9, 1.65],
 | 
						|
    [6.44, 4.84],
 | 
						|
  ];
 | 
						|
 | 
						|
  it("point on curve", () => {
 | 
						|
    expect(pointOnCurve(curve[0], curve)).toBe(true);
 | 
						|
    expect(pointOnCurve(curve[3], curve)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnCurve([2, 4], curve, 0.1)).toBe(true);
 | 
						|
    expect(pointOnCurve([4, 4.4], curve, 0.1)).toBe(true);
 | 
						|
    expect(pointOnCurve([5.6, 3.85], curve, 0.1)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnCurve([5.6, 4], curve, 0.1)).toBe(false);
 | 
						|
    expect(pointOnCurve(curve[1], curve, 0.1)).toBe(false);
 | 
						|
    expect(pointOnCurve(curve[2], curve, 0.1)).toBe(false);
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
describe("point and ellipse", () => {
 | 
						|
  const ellipse: Ellipse = {
 | 
						|
    center: [0, 0],
 | 
						|
    angle: 0,
 | 
						|
    halfWidth: 2,
 | 
						|
    halfHeight: 1,
 | 
						|
  };
 | 
						|
 | 
						|
  it("point on ellipse", () => {
 | 
						|
    [
 | 
						|
      [0, 1],
 | 
						|
      [0, -1],
 | 
						|
      [2, 0],
 | 
						|
      [-2, 0],
 | 
						|
    ].forEach((point) => {
 | 
						|
      expect(pointOnEllipse(point as Point, ellipse)).toBe(true);
 | 
						|
    });
 | 
						|
    expect(pointOnEllipse([-1.4, 0.7], ellipse, 0.1)).toBe(true);
 | 
						|
    expect(pointOnEllipse([-1.4, 0.71], ellipse, 0.01)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnEllipse([1.4, 0.7], ellipse, 0.1)).toBe(true);
 | 
						|
    expect(pointOnEllipse([1.4, 0.71], ellipse, 0.01)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnEllipse([1, -0.86], ellipse, 0.1)).toBe(true);
 | 
						|
    expect(pointOnEllipse([1, -0.86], ellipse, 0.01)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnEllipse([-1, -0.86], ellipse, 0.1)).toBe(true);
 | 
						|
    expect(pointOnEllipse([-1, -0.86], ellipse, 0.01)).toBe(true);
 | 
						|
 | 
						|
    expect(pointOnEllipse([-1, 0.8], ellipse)).toBe(false);
 | 
						|
    expect(pointOnEllipse([1, -0.8], ellipse)).toBe(false);
 | 
						|
  });
 | 
						|
 | 
						|
  it("point in ellipse", () => {
 | 
						|
    [
 | 
						|
      [0, 1],
 | 
						|
      [0, -1],
 | 
						|
      [2, 0],
 | 
						|
      [-2, 0],
 | 
						|
    ].forEach((point) => {
 | 
						|
      expect(pointInEllipse(point as Point, ellipse)).toBe(true);
 | 
						|
    });
 | 
						|
 | 
						|
    expect(pointInEllipse([-1, 0.8], ellipse)).toBe(true);
 | 
						|
    expect(pointInEllipse([1, -0.8], ellipse)).toBe(true);
 | 
						|
 | 
						|
    expect(pointInEllipse([-1, 1], ellipse)).toBe(false);
 | 
						|
    expect(pointInEllipse([-1.4, 0.8], ellipse)).toBe(false);
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
describe("line and line", () => {
 | 
						|
  const lineA: Line = [
 | 
						|
    [1, 4],
 | 
						|
    [3, 4],
 | 
						|
  ];
 | 
						|
  const lineB: Line = [
 | 
						|
    [2, 1],
 | 
						|
    [2, 7],
 | 
						|
  ];
 | 
						|
  const lineC: Line = [
 | 
						|
    [1, 8],
 | 
						|
    [3, 8],
 | 
						|
  ];
 | 
						|
  const lineD: Line = [
 | 
						|
    [1, 8],
 | 
						|
    [3, 8],
 | 
						|
  ];
 | 
						|
  const lineE: Line = [
 | 
						|
    [1, 9],
 | 
						|
    [3, 9],
 | 
						|
  ];
 | 
						|
  const lineF: Line = [
 | 
						|
    [1, 2],
 | 
						|
    [3, 4],
 | 
						|
  ];
 | 
						|
  const lineG: Line = [
 | 
						|
    [0, 1],
 | 
						|
    [2, 3],
 | 
						|
  ];
 | 
						|
 | 
						|
  it("intersection", () => {
 | 
						|
    expect(lineIntersectsLine(lineA, lineB)).toBe(true);
 | 
						|
    expect(lineIntersectsLine(lineA, lineC)).toBe(false);
 | 
						|
    expect(lineIntersectsLine(lineB, lineC)).toBe(false);
 | 
						|
    expect(lineIntersectsLine(lineC, lineD)).toBe(true);
 | 
						|
    expect(lineIntersectsLine(lineE, lineD)).toBe(false);
 | 
						|
    expect(lineIntersectsLine(lineF, lineG)).toBe(true);
 | 
						|
  });
 | 
						|
});
 |