/
vshmidt
/
label-studio
Обзор
Документация
Войти
/
vshmidt
/
label-studio
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
web/libs/editor/src/components/KonvaVector/utils.ts
278 строк
9 KB
Raul Martin
chore: echo-425: migrate to biome 2 to have the possibility to add plugings (#9385)
13 фев 2026, 07:27
Не верифицирован
13 фев 2026, 07:27
d0fc61d
Код
Авторство
О чём код?
import type { BezierPoint, SimplePoint, PointInput, Point } from "./types"; import { nanoid } from "nanoid"; // Calculate closest point on a line segment export const getClosestPointOnLine = (p: Point, a: Point, b: Point): Point => { const ax = a.x; const ay = a.y; const bx = b.x; const by = b.y; const px = p.x; const py = p.y; const A = px - ax; const B = py - ay; const C = bx - ax; const D = by - ay; const dot = A * C + B * D; const lenSq = C * C + D * D; let param = -1; if (lenSq !== 0) param = dot / lenSq; let xx: number; let yy: number; if (param < 0) { xx = ax; yy = ay; } else if (param > 1) { xx = bx; yy = by; } else { xx = ax + param * C; yy = ay + param * D; } return { x: xx, y: yy }; }; // Calculate closest point on a Bezier curve using numerical approximation export const getClosestPointOnBezierCurve = (p: Point, p0: Point, p1: Point, p2: Point, p3: Point): Point => { let closestPoint = p0; let minDistance = Number.POSITIVE_INFINITY; const steps = 200; // Increased precision for smoother curve following for (let i = 0; i <= steps; i++) { const t = i / steps; const x = (1 - t) ** 3 * p0.x + 3 * (1 - t) ** 2 * t * p1.x + 3 * (1 - t) * t ** 2 * p2.x + t ** 3 * p3.x; const y = (1 - t) ** 3 * p0.y + 3 * (1 - t) ** 2 * t * p1.y + 3 * (1 - t) * t ** 2 * p2.y + t ** 3 * p3.y; const distance = Math.sqrt((p.x - x) ** 2 + (p.y - y) ** 2); if (distance < minDistance) { minDistance = distance; closestPoint = { x, y }; } } return closestPoint; }; // Generate a unique ID for a point using nanoid export const generatePointId = (): string => { return nanoid(); }; /** * Convert complex BezierPoint format to simple point format * @param bezierPoints Array of BezierPoint objects * @returns Array of [x, y] coordinates */ export const convertBezierToSimplePoints = (bezierPoints: BezierPoint[]): SimplePoint[] => { return bezierPoints.map((point) => [point.x, point.y]); }; /** * Check if a point is in simple format * @param point Point to check * @returns True if point is in [x, y] format */ export const isSimplePoint = (point: PointInput): point is SimplePoint => { return Array.isArray(point) && point.length === 2 && typeof point[0] === "number" && typeof point[1] === "number"; }; /** * Check if a point is in complex format * @param point Point to check * @returns True if point is a BezierPoint object */ export const isBezierPoint = (point: PointInput): point is BezierPoint => { return typeof point === "object" && point !== null && "x" in point && "y" in point; }; /** * Normalize input points to BezierPoint format * @param points Array of points in either simple or complex format * @returns Array of normalized BezierPoint objects * @throws Error if point format is invalid */ export const normalizePoints = (points: PointInput[]): BezierPoint[] => { let lastPointId: string | undefined; return points.map((point, index) => { if (isSimplePoint(point)) { // Convert simple point to BezierPoint const newPoint = { id: generatePointId(), prevPointId: index > 0 ? lastPointId : undefined, x: point[0], y: point[1], isBezier: false, disconnected: false, isBranching: false, }; lastPointId = newPoint.id; return newPoint; } if (isBezierPoint(point)) { // Already in BezierPoint format, ensure it has proper prevPointId const newPoint = { ...point, id: point.id || generatePointId(), prevPointId: point.prevPointId || (index > 0 ? lastPointId : undefined), }; lastPointId = newPoint.id; return newPoint; } // Fallback for any other format throw new Error(`Invalid point format at index ${index}: ${JSON.stringify(point)}`); }); }; /** * Point-in-polygon test using ray casting algorithm with Bezier curve support * @param point - The point to test * @param polygon - Array of polygon vertices with potential Bezier curves * @returns True if point is inside the polygon */ export const isPointInPolygon = (point: Point, polygon: BezierPoint[]): boolean => { if (polygon.length < 3) return false; let inside = false; const x = point.x; const y = point.y; // Create a map for quick point lookup const pointMap = new Map<string, BezierPoint>(); for (const vertex of polygon) { pointMap.set(vertex.id, vertex); } // Check each edge of the polygon for (let i = 0; i < polygon.length; i++) { const currentPoint = polygon[i]; const prevPoint = currentPoint.prevPointId ? pointMap.get(currentPoint.prevPointId) : null; if (!prevPoint) continue; // Check if this edge intersects with the horizontal ray from the test point const intersects = checkRayIntersectionWithEdge(point, prevPoint, currentPoint); if (intersects) { inside = !inside; } } return inside; }; /** * Check if a horizontal ray from the test point intersects with a polygon edge * Handles both straight lines and Bezier curves */ const checkRayIntersectionWithEdge = (testPoint: Point, startPoint: BezierPoint, endPoint: BezierPoint): boolean => { const x = testPoint.x; const y = testPoint.y; // For straight line edges if (!startPoint.isBezier && !endPoint.isBezier) { return checkRayIntersectionWithLine(testPoint, startPoint, endPoint); } // For Bezier curve edges, we need to sample points along the curve // and check intersections with line segments between sample points const samples = 20; // Number of sample points along the curve let lastPoint = startPoint; for (let i = 1; i <= samples; i++) { const t = i / samples; const currentPoint = getBezierPointAtT(startPoint, endPoint, t); // Check intersection with line segment from lastPoint to currentPoint if (checkRayIntersectionWithLine(testPoint, lastPoint, currentPoint)) { return true; } lastPoint = currentPoint; } return false; }; /** * Check if a horizontal ray from the test point intersects with a straight line segment */ const checkRayIntersectionWithLine = (testPoint: Point, startPoint: Point, endPoint: Point): boolean => { const x = testPoint.x; const y = testPoint.y; const x1 = startPoint.x; const y1 = startPoint.y; const x2 = endPoint.x; const y2 = endPoint.y; // Ensure y1 <= y2 for consistent intersection checking if (y1 > y2) { return checkRayIntersectionWithLine(testPoint, endPoint, startPoint); } // Ray doesn't intersect if: // 1. The test point's y is not between the line segment's y values // 2. The line segment is horizontal (y1 === y2) if (y < y1 || y > y2 || y1 === y2) { return false; } // Calculate the x-coordinate where the horizontal ray intersects the line const intersectionX = x1 + ((y - y1) * (x2 - x1)) / (y2 - y1); // The ray intersects if the intersection point is to the right of the test point return intersectionX > x; }; /** * Get a point on a Bezier curve at parameter t * Handles different Bezier configurations */ const getBezierPointAtT = (startPoint: BezierPoint, endPoint: BezierPoint, t: number): Point => { // Determine control points based on Bezier configuration let cp1: Point; let cp2: Point; if (startPoint.isBezier && startPoint.controlPoint2 && endPoint.isBezier && endPoint.controlPoint1) { // Full Bezier curve - both points have control points cp1 = startPoint.controlPoint2; cp2 = endPoint.controlPoint1; } else if (startPoint.isBezier && startPoint.controlPoint2) { // Partial Bezier curve - only startPoint has controlPoint2 const dx = endPoint.x - startPoint.x; const dy = endPoint.y - startPoint.y; cp1 = startPoint.controlPoint2; cp2 = { x: endPoint.x - dx * 0.3, y: endPoint.y - dy * 0.3 }; } else if (endPoint.isBezier && endPoint.controlPoint1) { // Partial Bezier curve - only endPoint has controlPoint1 const dx = endPoint.x - startPoint.x; const dy = endPoint.y - startPoint.y; cp1 = { x: startPoint.x + dx * 0.3, y: startPoint.y + dy * 0.3 }; cp2 = endPoint.controlPoint1; } else { // No Bezier curve, return interpolated point on straight line return { x: startPoint.x + t * (endPoint.x - startPoint.x), y: startPoint.y + t * (endPoint.y - startPoint.y), }; } // Calculate Bezier curve point using cubic Bezier formula const u = 1 - t; const tt = t * t; const uu = u * u; const uuu = uu * u; const ttt = tt * t; return { x: uuu * startPoint.x + 3 * uu * t * cp1.x + 3 * u * tt * cp2.x + ttt * endPoint.x, y: uuu * startPoint.y + 3 * uu * t * cp1.y + 3 * u * tt * cp2.y + ttt * endPoint.y, }; };