mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Fill a looped curve with the selected background color (#1315)
This commit is contained in:
parent
fe6f482e96
commit
57bbc9fe55
11 changed files with 240 additions and 32 deletions
107
src/math.ts
107
src/math.ts
|
@ -1,4 +1,5 @@
|
|||
import { Point } from "./types";
|
||||
import { LINE_CONFIRM_THRESHOLD } from "./constants";
|
||||
|
||||
// https://stackoverflow.com/a/6853926/232122
|
||||
export function distanceBetweenPointAndSegment(
|
||||
|
@ -144,3 +145,109 @@ export const getPointOnAPath = (point: Point, path: Point[]) => {
|
|||
|
||||
return null;
|
||||
};
|
||||
|
||||
export function distance2d(x1: number, y1: number, x2: number, y2: number) {
|
||||
const xd = x2 - x1;
|
||||
const yd = y2 - y1;
|
||||
return Math.hypot(xd, yd);
|
||||
}
|
||||
|
||||
// Checks if the first and last point are close enough
|
||||
// to be considered a loop
|
||||
export function isPathALoop(points: Point[]): boolean {
|
||||
if (points.length >= 3) {
|
||||
const [firstPoint, lastPoint] = [points[0], points[points.length - 1]];
|
||||
return (
|
||||
distance2d(firstPoint[0], firstPoint[1], lastPoint[0], lastPoint[1]) <=
|
||||
LINE_CONFIRM_THRESHOLD
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Draw a line from the point to the right till infiinty
|
||||
// Check how many lines of the polygon does this infinite line intersects with
|
||||
// If the number of intersections is odd, point is in the polygon
|
||||
export function isPointInPolygon(
|
||||
points: Point[],
|
||||
x: number,
|
||||
y: number,
|
||||
): boolean {
|
||||
const vertices = points.length;
|
||||
|
||||
// There must be at least 3 vertices in polygon
|
||||
if (vertices < 3) {
|
||||
return false;
|
||||
}
|
||||
const extreme: Point = [Number.MAX_SAFE_INTEGER, y];
|
||||
const p: Point = [x, y];
|
||||
let count = 0;
|
||||
for (let i = 0; i < vertices; i++) {
|
||||
const current = points[i];
|
||||
const next = points[(i + 1) % vertices];
|
||||
if (doIntersect(current, next, p, extreme)) {
|
||||
if (orientation(current, p, next) === 0) {
|
||||
return onSegment(current, p, next);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
// true if count is off
|
||||
return count % 2 === 1;
|
||||
}
|
||||
|
||||
// Check if q lies on the line segment pr
|
||||
function onSegment(p: Point, q: Point, r: Point) {
|
||||
return (
|
||||
q[0] <= Math.max(p[0], r[0]) &&
|
||||
q[0] >= Math.min(p[0], r[0]) &&
|
||||
q[1] <= Math.max(p[1], r[1]) &&
|
||||
q[1] >= Math.min(p[1], r[1])
|
||||
);
|
||||
}
|
||||
|
||||
// For the ordered points p, q, r, return
|
||||
// 0 if p, q, r are collinear
|
||||
// 1 if Clockwise
|
||||
// 2 if counterclickwise
|
||||
function orientation(p: Point, q: Point, r: Point) {
|
||||
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
||||
if (val === 0) {
|
||||
return 0;
|
||||
}
|
||||
return val > 0 ? 1 : 2;
|
||||
}
|
||||
|
||||
// Check is p1q1 intersects with p2q2
|
||||
function doIntersect(p1: Point, q1: Point, p2: Point, q2: Point) {
|
||||
const o1 = orientation(p1, q1, p2);
|
||||
const o2 = orientation(p1, q1, q2);
|
||||
const o3 = orientation(p2, q2, p1);
|
||||
const o4 = orientation(p2, q2, q1);
|
||||
|
||||
if (o1 !== o2 && o3 !== o4) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// p1, q1 and p2 are colinear and p2 lies on segment p1q1
|
||||
if (o1 === 0 && onSegment(p1, p2, q1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// p1, q1 and p2 are colinear and q2 lies on segment p1q1
|
||||
if (o2 === 0 && onSegment(p1, q2, q1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// p2, q2 and p1 are colinear and p1 lies on segment p2q2
|
||||
if (o3 === 0 && onSegment(p2, p1, q2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// p2, q2 and q1 are colinear and q1 lies on segment p2q2
|
||||
if (o4 === 0 && onSegment(p2, q1, q2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue