Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove circle engine and move function getNearestPointBetwe… #847

Merged
merged 1 commit into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/violet-olives-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@plait/draw': patch
---

remove circle engine

move function getNearestPointBetweenPointAndEllipse into math file
45 changes: 45 additions & 0 deletions packages/core/src/utils/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,51 @@ export function getNearestPointBetweenPointAndSegments(point: Point, points: Poi
return result;
}

export function getNearestPointBetweenPointAndEllipse(point: Point, center: Point, rx: number, ry: number, rotation: number = 0): Point {
const rectangleClient = {
x: center[0] - rx,
y: center[1] - ry,
height: ry * 2,
width: rx * 2
};
// https://stackoverflow.com/a/46007540/232122
const px = Math.abs(point[0] - rectangleClient.x - rectangleClient.width / 2);
const py = Math.abs(point[1] - rectangleClient.y - rectangleClient.height / 2);

let tx = 0.707;
let ty = 0.707;

const a = Math.abs(rectangleClient.width) / 2;
const b = Math.abs(rectangleClient.height) / 2;

[0, 1, 2, 3].forEach(x => {
const xx = a * tx;
const yy = b * ty;

const ex = ((a * a - b * b) * tx ** 3) / a;
const ey = ((b * b - a * a) * ty ** 3) / b;

const rx = xx - ex;
const ry = yy - ey;

const qx = px - ex;
const qy = py - ey;

const r = Math.hypot(ry, rx);
const q = Math.hypot(qy, qx);

tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
const t = Math.hypot(ty, tx);
tx /= t;
ty /= t;
});
const signX = point[0] > center[0] ? 1 : -1;
const signY = point[1] > center[1] ? 1 : -1;

return [center[0] + a * tx * signX, center[1] + b * ty * signY];
}

export function rotate(x1: number, y1: number, x2: number, y2: number, angle: number) {
// 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
// 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
Expand Down
68 changes: 0 additions & 68 deletions packages/draw/src/engines/basic-shapes/circle.ts

This file was deleted.

108 changes: 64 additions & 44 deletions packages/draw/src/engines/basic-shapes/ellipse.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
import { Point } from '@plait/core';
import { ShapeEngine } from '../../interfaces';
import { createEllipseEngine } from './circle';
import {
PlaitBoard,
Point,
PointOfRectangle,
RectangleClient,
getEllipseTangentSlope,
getVectorFromPointAndSlope,
isPointInEllipse,
getNearestPointBetweenPointAndEllipse
} from '@plait/core';
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { getTextRectangle } from '../../utils';

export const EllipseEngine: ShapeEngine = createEllipseEngine();
export interface CreateEllipseOptions {
draw?: (board: PlaitBoard, rectangle: RectangleClient, options: Options) => SVGGElement;
getTextRectangle?: (element: PlaitGeometry) => RectangleClient;
}

export function getNearestPointBetweenPointAndEllipse(point: Point, center: Point, rx: number, ry: number, rotation: number = 0): Point {
const rectangleClient = {
x: center[0] - rx,
y: center[1] - ry,
height: ry * 2,
width: rx * 2
export function createEllipseEngine(createOptions?: CreateEllipseOptions): ShapeEngine {
const engine: ShapeEngine = {
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
const rs = PlaitBoard.getRoughSVG(board);
return rs.ellipse(centerPoint[0], centerPoint[1], rectangle.width, rectangle.height, { ...options, fillStyle: 'solid' });
},
isInsidePoint(rectangle: RectangleClient, point: Point) {
const centerPoint: Point = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
},
getCornerPoints(rectangle: RectangleClient) {
return RectangleClient.getEdgeCenterPoints(rectangle);
},
getNearestPoint(rectangle: RectangleClient, point: Point) {
const centerPoint: Point = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
},
getTangentVectorByConnectionPoint(rectangle: RectangleClient, pointOfRectangle: PointOfRectangle) {
const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
const centerPoint: Point = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
const a = rectangle.width / 2;
const b = rectangle.height / 2;
const slope = getEllipseTangentSlope(point[0], point[1], a, b) as any;
const vector = getVectorFromPointAndSlope(point[0], point[1], slope);
return vector;
},
getConnectorPoints(rectangle: RectangleClient) {
return RectangleClient.getEdgeCenterPoints(rectangle);
},
getTextRectangle(element: PlaitGeometry) {
const rectangle = getTextRectangle(element);
const width = rectangle.width;
rectangle.width = (rectangle.width * 3) / 4;
rectangle.x += width / 8;
return rectangle;
}
};
// https://stackoverflow.com/a/46007540/232122
const px = Math.abs(point[0] - rectangleClient.x - rectangleClient.width / 2);
const py = Math.abs(point[1] - rectangleClient.y - rectangleClient.height / 2);

let tx = 0.707;
let ty = 0.707;

const a = Math.abs(rectangleClient.width) / 2;
const b = Math.abs(rectangleClient.height) / 2;

[0, 1, 2, 3].forEach(x => {
const xx = a * tx;
const yy = b * ty;

const ex = ((a * a - b * b) * tx ** 3) / a;
const ey = ((b * b - a * a) * ty ** 3) / b;

const rx = xx - ex;
const ry = yy - ey;
if (createOptions?.draw) {
engine.draw = createOptions.draw;
}
if (createOptions?.getTextRectangle) {
engine.getTextRectangle = createOptions.getTextRectangle;
}

const qx = px - ex;
const qy = py - ey;

const r = Math.hypot(ry, rx);
const q = Math.hypot(qy, qx);

tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
const t = Math.hypot(ty, tx);
tx /= t;
ty /= t;
});
const signX = point[0] > center[0] ? 1 : -1;
const signY = point[1] > center[1] ? 1 : -1;

return [center[0] + a * tx * signX, center[1] + b * ty * signY];
return engine;
}

export const EllipseEngine: ShapeEngine = createEllipseEngine();
4 changes: 2 additions & 2 deletions packages/draw/src/engines/basic-shapes/round-rectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
RectangleClient,
drawRoundRectangle,
getNearestPointBetweenPointAndSegments,
isPointInRoundRectangle
isPointInRoundRectangle,
getNearestPointBetweenPointAndEllipse
} from '@plait/core';
import { ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { getNearestPointBetweenPointAndEllipse } from './ellipse';
import { RectangleEngine } from './rectangle';
import { getPolygonEdgeByConnectionPoint } from '../../utils/polygon';

Expand Down
4 changes: 2 additions & 2 deletions packages/draw/src/engines/flowchart/delay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import {
getNearestPointBetweenPointAndSegments,
getVectorFromPointAndSlope,
isPointInEllipse,
setStrokeLinecap
setStrokeLinecap,
getNearestPointBetweenPointAndEllipse
} from '@plait/core';
import { ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { RectangleEngine } from '../basic-shapes/rectangle';
import { getNearestPointBetweenPointAndEllipse } from '../basic-shapes/ellipse';

export const DelayEngine: ShapeEngine = {
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
Expand Down
2 changes: 1 addition & 1 deletion packages/draw/src/engines/flowchart/or.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PlaitBoard, RectangleClient } from '@plait/core';
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { getTextRectangle } from '../../utils';
import { createEllipseEngine } from '../basic-shapes/circle';
import { createEllipseEngine } from '../basic-shapes/ellipse';

export const OrEngine: ShapeEngine = createEllipseEngine({
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
Expand Down
4 changes: 2 additions & 2 deletions packages/draw/src/engines/flowchart/stored-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
getNearestPointBetweenPointAndSegments,
getVectorFromPointAndSlope,
isPointInEllipse,
setStrokeLinecap
setStrokeLinecap,
getNearestPointBetweenPointAndEllipse
} from '@plait/core';
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { RectangleEngine } from '../basic-shapes/rectangle';
import { getNearestPointBetweenPointAndEllipse } from '../basic-shapes/ellipse';
import { getTextRectangle } from '../../utils';

export const StoredDataEngine: ShapeEngine = {
Expand Down
2 changes: 1 addition & 1 deletion packages/draw/src/engines/flowchart/summing-junction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PlaitBoard, RectangleClient, getCrossingPointsBetweenEllipseAndSegment
import { PlaitGeometry, ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { getTextRectangle } from '../../utils';
import { createEllipseEngine } from '../basic-shapes/circle';
import { createEllipseEngine } from '../basic-shapes/ellipse';

export const SummingJunctionEngine: ShapeEngine = createEllipseEngine({
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
Expand Down
4 changes: 2 additions & 2 deletions packages/draw/src/engines/flowchart/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {
getEllipseTangentSlope,
getNearestPointBetweenPointAndSegments,
getVectorFromPointAndSlope,
isPointInRoundRectangle
isPointInRoundRectangle,
getNearestPointBetweenPointAndEllipse
} from '@plait/core';
import { ShapeEngine } from '../../interfaces';
import { Options } from 'roughjs/bin/core';
import { getNearestPointBetweenPointAndEllipse } from '../basic-shapes/ellipse';

export const TerminalEngine: ShapeEngine = {
draw(board: PlaitBoard, rectangle: RectangleClient, options: Options) {
Expand Down
Loading