mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-10-31 02:44:50 +01:00 
			
		
		
		
	 bbdcd30a73
			
		
	
	bbdcd30a73
	
	
	
		
			
			* 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);
 | |
|   });
 | |
| });
 |