reladraw 0.17.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/SYNTAX.md +115 -12
- package/dist/checks.js +30 -9
- package/dist/cli.js +188 -1
- package/dist/format-settings.d.ts +60 -0
- package/dist/format-settings.js +250 -0
- package/dist/format.d.ts +14 -0
- package/dist/format.js +511 -0
- package/dist/icons.d.ts +13 -13
- package/dist/icons.js +61 -15
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/lexer.d.ts +8 -0
- package/dist/lexer.js +19 -6
- package/dist/lines.d.ts +8 -0
- package/dist/lines.js +50 -4
- package/dist/outline.d.ts +123 -0
- package/dist/outline.js +564 -0
- package/dist/parser.d.ts +25 -1
- package/dist/parser.js +95 -10
- package/dist/place.d.ts +5 -0
- package/dist/place.js +44 -14
- package/dist/render.js +43 -18
- package/dist/resolve.js +43 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export * from './grammar.js';
|
|
|
6
6
|
export * from './measure.js';
|
|
7
7
|
export * from './model.js';
|
|
8
8
|
export { parse } from './parser.js';
|
|
9
|
+
export { format } from './format.js';
|
|
10
|
+
export { DEFAULT_FORMAT, readFormatSettings, SETTINGS, SETTINGS_FILE, settingsFileText, type FormatSettings, } from './format-settings.js';
|
|
9
11
|
export { resolve, type ResolveOptions } from './resolve.js';
|
|
10
12
|
export { render, type RenderOptions } from './render.js';
|
|
11
13
|
export { DARK_THEME, DEFAULT_THEME, THEMES, THEME_NAMES, type Theme } from './themes.js';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ export * from './grammar.js';
|
|
|
6
6
|
export * from './measure.js';
|
|
7
7
|
export * from './model.js';
|
|
8
8
|
export { parse } from './parser.js';
|
|
9
|
+
export { format } from './format.js';
|
|
10
|
+
export { DEFAULT_FORMAT, readFormatSettings, SETTINGS, SETTINGS_FILE, settingsFileText, } from './format-settings.js';
|
|
9
11
|
export { resolve } from './resolve.js';
|
|
10
12
|
export { render } from './render.js';
|
|
11
13
|
export { DARK_THEME, DEFAULT_THEME, THEMES, THEME_NAMES } from './themes.js';
|
package/dist/lexer.d.ts
CHANGED
|
@@ -11,6 +11,14 @@ export interface Token {
|
|
|
11
11
|
* about the word can quote what the author typed.
|
|
12
12
|
*/
|
|
13
13
|
joined?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Where the token was written: from `start` up to `end` in the line given to
|
|
16
|
+
* `tokenizeLine`, quotes included. The formatter copies each token back out
|
|
17
|
+
* of its line by these, so nothing it writes is respelled. Absent on a token
|
|
18
|
+
* made up by the parser rather than read from a line.
|
|
19
|
+
*/
|
|
20
|
+
start?: number;
|
|
21
|
+
end?: number;
|
|
14
22
|
}
|
|
15
23
|
/**
|
|
16
24
|
* A `"""` string still open at the end of the text given. `parse` catches this
|
package/dist/lexer.js
CHANGED
|
@@ -48,13 +48,13 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
|
|
|
48
48
|
break;
|
|
49
49
|
if (ch === '(') {
|
|
50
50
|
depth += 1;
|
|
51
|
-
tokens.push({ text: '(', quoted: false });
|
|
51
|
+
tokens.push({ text: '(', quoted: false, start: i, end: i + 1 });
|
|
52
52
|
i += 1;
|
|
53
53
|
continue;
|
|
54
54
|
}
|
|
55
55
|
if (ch === ')' && depth > 0) {
|
|
56
56
|
depth -= 1;
|
|
57
|
-
tokens.push({ text: ')', quoted: false });
|
|
57
|
+
tokens.push({ text: ')', quoted: false, start: i, end: i + 1 });
|
|
58
58
|
i += 1;
|
|
59
59
|
continue;
|
|
60
60
|
}
|
|
@@ -65,11 +65,12 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
|
|
|
65
65
|
const end = line.indexOf('"""', i + 3);
|
|
66
66
|
if (end === -1)
|
|
67
67
|
throw new OpenString('this """ string is never closed — end it with """', lineNumber);
|
|
68
|
-
tokens.push({ text: line.slice(i + 3, end), quoted: true, triple: true });
|
|
68
|
+
tokens.push({ text: line.slice(i + 3, end), quoted: true, triple: true, start: i, end: end + 3 });
|
|
69
69
|
i = end + 3;
|
|
70
70
|
continue;
|
|
71
71
|
}
|
|
72
72
|
if (ch === '"') {
|
|
73
|
+
const start = i;
|
|
73
74
|
let text = '';
|
|
74
75
|
i += 1;
|
|
75
76
|
let closed = false;
|
|
@@ -96,7 +97,7 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
|
|
|
96
97
|
}
|
|
97
98
|
if (!closed)
|
|
98
99
|
throw new SourceError('unterminated string', lineNumber);
|
|
99
|
-
tokens.push({ text, quoted: true });
|
|
100
|
+
tokens.push({ text, quoted: true, start, end: i });
|
|
100
101
|
continue;
|
|
101
102
|
}
|
|
102
103
|
const start = i;
|
|
@@ -111,6 +112,11 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
|
|
|
111
112
|
break;
|
|
112
113
|
text += c;
|
|
113
114
|
i += 1;
|
|
115
|
+
// A comma ends a word, so `rounded,path: square` reads as
|
|
116
|
+
// `rounded, path: square`. Not inside a word's own bracket, which keeps
|
|
117
|
+
// `rgb(20,20,20)` whole.
|
|
118
|
+
if (c === ',' && !text.includes('('))
|
|
119
|
+
break;
|
|
114
120
|
}
|
|
115
121
|
// `gap:tight` is `gap: tight` with no space, since how much whitespace there
|
|
116
122
|
// is never matters. A word straight after a key is its value and is left
|
|
@@ -120,11 +126,18 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
|
|
|
120
126
|
const previous = tokens[tokens.length - 1];
|
|
121
127
|
const joined = previous && isAttrKey(previous) ? null : JOINED_KEY.exec(text);
|
|
122
128
|
if (joined) {
|
|
123
|
-
tokens.push({ text: joined[1], quoted: false, joined: text });
|
|
129
|
+
tokens.push({ text: joined[1], quoted: false, joined: text, start, end: start + joined[1].length });
|
|
124
130
|
i = start + joined[1].length;
|
|
125
131
|
continue;
|
|
126
132
|
}
|
|
127
|
-
|
|
133
|
+
// A comma written apart from its word, `start , above`, is the comma of
|
|
134
|
+
// `start, above`. A bracket or a quoted text keeps its comma separate, so
|
|
135
|
+
// neither is changed by what follows it.
|
|
136
|
+
if (text === ',' && previous && !previous.quoted && !isAttrKey(previous) && !/^[()]$/.test(previous.text) && !previous.text.endsWith(',')) {
|
|
137
|
+
previous.text += ',';
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
tokens.push({ text, quoted: false, start, end: i });
|
|
128
141
|
}
|
|
129
142
|
return tokens;
|
|
130
143
|
}
|
package/dist/lines.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ export interface Face {
|
|
|
11
11
|
height: number;
|
|
12
12
|
/** A circle is drawn in this square, so a line meets the circle. */
|
|
13
13
|
round: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Any other outline but a rectangle's, as a polygon on the page, with the
|
|
16
|
+
* shape's middle: a line meets the polygon, and the lines from the middle
|
|
17
|
+
* to the box's corners cut it into its four sides.
|
|
18
|
+
*/
|
|
19
|
+
outline?: Point[];
|
|
20
|
+
middle?: Point;
|
|
14
21
|
}
|
|
15
22
|
export type Side = 'top' | 'bottom' | 'left' | 'right';
|
|
16
23
|
/** One piece of a drawn line, from where the last one ended: straight, or a cubic. */
|
|
@@ -69,6 +76,7 @@ export declare function planSides(layout: Layout): {
|
|
|
69
76
|
export declare function faceOfNode(node: LayoutNode): Face;
|
|
70
77
|
/** The point a share of the way along a polyline, bends included, or its start or end. */
|
|
71
78
|
export declare function alongLength(trace: Point[], at: number | 'start' | 'end'): Point;
|
|
79
|
+
/** A face's middle: its box's, or a shape's own, which is a triangle's a third of the way from its base. */
|
|
72
80
|
export declare function centerOf(face: Face): Point;
|
|
73
81
|
/** The points with repeats and points in line with both neighbors dropped. */
|
|
74
82
|
export declare function tidyCorners(points: Point[]): Point[];
|
package/dist/lines.js
CHANGED
|
@@ -16,6 +16,7 @@ import { GAPS } from './constants.js';
|
|
|
16
16
|
import { EDGE_ORDER_KEYS, PART_SIDES, WAYS, isPosition } from './ast.js';
|
|
17
17
|
import { SourceError } from './errors.js';
|
|
18
18
|
import { gapPixels } from './place.js';
|
|
19
|
+
import { isBoxy, isRound, lineCrossings, middleOf, rayExit, shapeOf, sideOfPoint, sideStretch, towardOutline } from './outline.js';
|
|
19
20
|
/**
|
|
20
21
|
* How far apart copies of one line run, like lanes on a road (6.5). A fixed
|
|
21
22
|
* step, so adding a copy widens the set by one lane and moves no other lane.
|
|
@@ -464,6 +465,9 @@ function meetOutline(face, at, way) {
|
|
|
464
465
|
if (disc >= 0)
|
|
465
466
|
hits.push(-b - Math.sqrt(disc), -b + Math.sqrt(disc));
|
|
466
467
|
}
|
|
468
|
+
else if (face.outline) {
|
|
469
|
+
hits.push(...lineCrossings(face.outline, at, way));
|
|
470
|
+
}
|
|
467
471
|
else {
|
|
468
472
|
const within = (value, low, size) => value >= low - 0.5 && value <= low + size + 0.5;
|
|
469
473
|
for (const x of [face.x, face.x + face.width]) {
|
|
@@ -497,6 +501,10 @@ function leaving(face, from, way) {
|
|
|
497
501
|
const t = -b + Math.sqrt(Math.max(0, b * b - (fx * fx + fy * fy - r * r)));
|
|
498
502
|
return { x: from.x + way.x * t, y: from.y + way.y * t };
|
|
499
503
|
}
|
|
504
|
+
if (face.outline) {
|
|
505
|
+
const t = rayExit(face.outline, from, way) ?? 0;
|
|
506
|
+
return { x: from.x + way.x * t, y: from.y + way.y * t };
|
|
507
|
+
}
|
|
500
508
|
const tx = way.x > 1e-9 ? (face.x + face.width - from.x) / way.x : way.x < -1e-9 ? (face.x - from.x) / way.x : Infinity;
|
|
501
509
|
const ty = way.y > 1e-9 ? (face.y + face.height - from.y) / way.y : way.y < -1e-9 ? (face.y - from.y) / way.y : Infinity;
|
|
502
510
|
const t = Math.max(0, Math.min(tx, ty));
|
|
@@ -576,13 +584,20 @@ const WAY_VECTOR = {
|
|
|
576
584
|
const MET_SIDE = { down: 'top', up: 'bottom', left: 'right', right: 'left' };
|
|
577
585
|
/** The drawn rectangle of a node. */
|
|
578
586
|
export function faceOfNode(node) {
|
|
579
|
-
|
|
587
|
+
const face = {
|
|
580
588
|
x: node.x,
|
|
581
589
|
y: node.y,
|
|
582
590
|
width: node.width,
|
|
583
591
|
height: node.height,
|
|
584
|
-
round: node.body.kind === 'shape' && node.body.outline
|
|
592
|
+
round: node.body.kind === 'shape' && isRound(node.body.outline, node.width, node.height),
|
|
585
593
|
};
|
|
594
|
+
if (node.body.kind === 'shape' && !isBoxy(node.body.outline) && !face.round) {
|
|
595
|
+
const { outline, look } = node.body;
|
|
596
|
+
face.outline = shapeOf(outline, look, node.width, node.height).polygon.map((p) => ({ x: node.x + p.x, y: node.y + p.y }));
|
|
597
|
+
const middle = middleOf(outline, look, node.width, node.height);
|
|
598
|
+
face.middle = { x: node.x + middle.x, y: node.y + middle.y };
|
|
599
|
+
}
|
|
600
|
+
return face;
|
|
586
601
|
}
|
|
587
602
|
function endOf(edge, which) {
|
|
588
603
|
const node = which === 'from' ? edge.from : edge.to;
|
|
@@ -1027,8 +1042,9 @@ function distance(a, b) {
|
|
|
1027
1042
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
1028
1043
|
}
|
|
1029
1044
|
// --- points on a box ------------------------------------------------------------
|
|
1045
|
+
/** A face's middle: its box's, or a shape's own, which is a triangle's a third of the way from its base. */
|
|
1030
1046
|
export function centerOf(face) {
|
|
1031
|
-
return { x: face.x + face.width / 2, y: face.y + face.height / 2 };
|
|
1047
|
+
return face.middle ?? { x: face.x + face.width / 2, y: face.y + face.height / 2 };
|
|
1032
1048
|
}
|
|
1033
1049
|
/** The sides a position sits on: `bottom-right` is on the bottom and the right, `top-center` on the top only. */
|
|
1034
1050
|
function cornerSides(position) {
|
|
@@ -1046,9 +1062,12 @@ function positionPoint(face, position) {
|
|
|
1046
1062
|
x: horizontal === 'left' ? face.x : horizontal === 'right' ? face.x + face.width : face.x + face.width / 2,
|
|
1047
1063
|
y: vertical === 'top' ? face.y : vertical === 'bottom' ? face.y + face.height : face.y + face.height / 2,
|
|
1048
1064
|
};
|
|
1049
|
-
// A circle has no corners; its corner is where the diagonal meets it.
|
|
1065
|
+
// A circle has no corners; its corner is where the diagonal meets it. On
|
|
1066
|
+
// another shape every point is where the line from its middle meets it.
|
|
1050
1067
|
if (face.round && vertical && horizontal)
|
|
1051
1068
|
return outlineToward(face, point);
|
|
1069
|
+
if (face.outline)
|
|
1070
|
+
return outlineToward(face, point);
|
|
1052
1071
|
return point;
|
|
1053
1072
|
}
|
|
1054
1073
|
/** A point a fraction of the way along a side, from its left or top end. */
|
|
@@ -1066,6 +1085,29 @@ function onSide(face, side, along) {
|
|
|
1066
1085
|
const angle = { right: turn, bottom: Math.PI / 2 - turn, left: Math.PI - turn, top: -Math.PI / 2 + turn }[side];
|
|
1067
1086
|
return { x: center.x + radius * Math.cos(angle), y: center.y + radius * Math.sin(angle) };
|
|
1068
1087
|
}
|
|
1088
|
+
if (face.outline) {
|
|
1089
|
+
// The side is the stretch of outline between the lines from the middle to
|
|
1090
|
+
// its two corners. `along` lands where the stretch passes it, so a line
|
|
1091
|
+
// down from the middle of one box's bottom meets the next square on; one
|
|
1092
|
+
// past the stretch's ends is placed on it in proportion instead.
|
|
1093
|
+
const stretch = sideStretch(face.outline, centerOf(face), face, side);
|
|
1094
|
+
const key = side === 'top' || side === 'bottom' ? 'x' : 'y';
|
|
1095
|
+
const low = key === 'x' ? face.x : face.y;
|
|
1096
|
+
const size = key === 'x' ? face.width : face.height;
|
|
1097
|
+
const values = stretch.map((p) => p[key]);
|
|
1098
|
+
const lo = Math.min(...values);
|
|
1099
|
+
const hi = Math.max(...values);
|
|
1100
|
+
const target = along >= lo && along <= hi ? along : lo + ((along - low) / size) * (hi - lo);
|
|
1101
|
+
for (let i = 1; i < stretch.length; i++) {
|
|
1102
|
+
const a = stretch[i - 1];
|
|
1103
|
+
const b = stretch[i];
|
|
1104
|
+
if ((a[key] - target) * (b[key] - target) <= 0 && a[key] !== b[key]) {
|
|
1105
|
+
const f = (target - a[key]) / (b[key] - a[key]);
|
|
1106
|
+
return { x: a.x + (b.x - a.x) * f, y: a.y + (b.y - a.y) * f };
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
return Math.abs(stretch[0][key] - target) < Math.abs(stretch[stretch.length - 1][key] - target) ? stretch[0] : stretch[stretch.length - 1];
|
|
1110
|
+
}
|
|
1069
1111
|
switch (side) {
|
|
1070
1112
|
case 'top':
|
|
1071
1113
|
return { x: along, y: face.y };
|
|
@@ -1089,6 +1131,8 @@ function outlineToward(face, target) {
|
|
|
1089
1131
|
const length = Math.hypot(dx, dy);
|
|
1090
1132
|
return { x: center.x + (dx / length) * radius, y: center.y + (dy / length) * radius };
|
|
1091
1133
|
}
|
|
1134
|
+
if (face.outline)
|
|
1135
|
+
return towardOutline(face.outline, center, target);
|
|
1092
1136
|
const scale = Math.min(dx === 0 ? Infinity : face.width / 2 / Math.abs(dx), dy === 0 ? Infinity : face.height / 2 / Math.abs(dy));
|
|
1093
1137
|
return { x: center.x + dx * scale, y: center.y + dy * scale };
|
|
1094
1138
|
}
|
|
@@ -1106,6 +1150,8 @@ function headingAt(face, at) {
|
|
|
1106
1150
|
const dy = at.y - center.y;
|
|
1107
1151
|
return Math.abs(dx) >= Math.abs(dy) ? SIDE_NORMAL[dx >= 0 ? 'right' : 'left'] : SIDE_NORMAL[dy >= 0 ? 'bottom' : 'top'];
|
|
1108
1152
|
}
|
|
1153
|
+
if (face.outline)
|
|
1154
|
+
return SIDE_NORMAL[sideOfPoint(centerOf(face), face, at)];
|
|
1109
1155
|
distances.sort((a, b) => a[0] - b[0]);
|
|
1110
1156
|
return SIDE_NORMAL[distances[0][1]];
|
|
1111
1157
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The geometry of every outline `shape:` names: where its edge runs, where its
|
|
3
|
+
* middle is, and how big it grows to hold its text.
|
|
4
|
+
*
|
|
5
|
+
* One place knows each shape, and the resolver, the line planner, the checks
|
|
6
|
+
* and the renderer all ask it, so they cannot disagree about where a diamond's
|
|
7
|
+
* edge is.
|
|
8
|
+
*
|
|
9
|
+
* A shape stretches to fill its box. What the box doesn't decide is at most one
|
|
10
|
+
* amount and one direction (a parallelogram's slant and which way it leans),
|
|
11
|
+
* and those are the settings in the shape's bracket. Amounts are fixed
|
|
12
|
+
* distances, not fractions of the box, as the document's fold always was.
|
|
13
|
+
*
|
|
14
|
+
* The rectangle-like outlines (`rectangle`, `document`, `flow-subprocess`) and
|
|
15
|
+
* a round `circle` keep the exact geometry they always had; every other
|
|
16
|
+
* outline is worked with as a polygon, its curves sampled finely enough that a
|
|
17
|
+
* line meeting one lands on the drawn curve to within a fraction of a pixel.
|
|
18
|
+
*/
|
|
19
|
+
/** A point, relative to whatever the caller says. */
|
|
20
|
+
export interface Point {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
}
|
|
24
|
+
/** How each setting in a shape's bracket is read. */
|
|
25
|
+
type SettingKind = 'distance' | 'flag' | readonly string[];
|
|
26
|
+
/**
|
|
27
|
+
* The settings each shape takes in its bracket, by name. A shape not listed
|
|
28
|
+
* takes none. The first word of a direction is the default.
|
|
29
|
+
*/
|
|
30
|
+
export declare const SHAPE_SETTINGS: Readonly<Record<string, Readonly<Record<string, SettingKind>>>>;
|
|
31
|
+
/** The settings a shape was given, read: distances in pixels, directions as words, flags as true. */
|
|
32
|
+
export interface ShapeLook {
|
|
33
|
+
fold?: number;
|
|
34
|
+
slant?: number;
|
|
35
|
+
lean?: string;
|
|
36
|
+
point?: number;
|
|
37
|
+
taper?: number;
|
|
38
|
+
narrow?: string;
|
|
39
|
+
aim?: string;
|
|
40
|
+
cap?: number;
|
|
41
|
+
lying?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Read a shape's bracket, refusing a setting the shape doesn't take and a
|
|
45
|
+
* value that isn't one. `written` holds the dotted keys as stored, `shape.slant`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function readShapeLook(outline: string, written: Record<string, string>, subject: string, line: number): ShapeLook;
|
|
48
|
+
/** How far inside each side a subprocess's bars stand. */
|
|
49
|
+
export declare const SUBPROCESS_INSET: number;
|
|
50
|
+
/** Whether an outline is a rectangle as far as placement and lines go. */
|
|
51
|
+
export declare function isBoxy(outline: string): boolean;
|
|
52
|
+
/** Whether an outline is drawn round in a square box, so the exact circle code applies. */
|
|
53
|
+
export declare function isRound(outline: string, width: number, height: number): boolean;
|
|
54
|
+
/** One outline at one size: the polygon it is worked with, and the SVG it is drawn as. Points are relative to the box's top-left. */
|
|
55
|
+
export interface Shape {
|
|
56
|
+
/** The outline as a closed polygon, for meeting lines and testing what is inside. */
|
|
57
|
+
polygon: Point[];
|
|
58
|
+
/** The path data, relative, drawn translated to the box. */
|
|
59
|
+
path: string;
|
|
60
|
+
/** Lines drawn inside the outline: a cylinder's near rim, a subprocess's bars. */
|
|
61
|
+
detail: string[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* An outline at a size. Rectangle-like outlines and the round circle are
|
|
65
|
+
* included so a caller can always ask, but the renderer draws those itself.
|
|
66
|
+
*/
|
|
67
|
+
export declare function shapeOf(outline: string, look: ShapeLook, w: number, h: number): Shape;
|
|
68
|
+
/**
|
|
69
|
+
* A path written relative to a box's top-left, moved to (x, y). Only the
|
|
70
|
+
* absolute commands `shapeOf` writes are handled: M, L, H, V, Q, T, A and Z.
|
|
71
|
+
*/
|
|
72
|
+
export declare function placePath(d: string, x: number, y: number): string;
|
|
73
|
+
/**
|
|
74
|
+
* The shape's own middle, where its text sits and its lines aim: the center of
|
|
75
|
+
* its area. On a symmetric shape that is the middle of its box; a triangle's is
|
|
76
|
+
* a third of the way from its base.
|
|
77
|
+
*/
|
|
78
|
+
export declare function middleOf(outline: string, look: ShapeLook, w: number, h: number): Point;
|
|
79
|
+
/** Whether a point is inside a polygon, by crossings. */
|
|
80
|
+
export declare function insideOutline(points: Point[], p: Point): boolean;
|
|
81
|
+
/** Whether a point is more than `distance` from every edge of a polygon. */
|
|
82
|
+
export declare function clearOf(points: Point[], p: Point, distance: number): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* The size an outline takes to hold a block `tw` by `th` (the text with its
|
|
85
|
+
* padding) at its middle: a first guess that is exact for most shapes, then
|
|
86
|
+
* grown a step at a time until the block fits. A rectangle-like outline and
|
|
87
|
+
* the round circle are sized by the resolver, as they always were.
|
|
88
|
+
*/
|
|
89
|
+
export declare function sizeFor(outline: string, look: ShapeLook, tw: number, th: number): {
|
|
90
|
+
width: number;
|
|
91
|
+
height: number;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Where the ray from `from` heading `way` first leaves a polygon, measured as
|
|
95
|
+
* the distance along the ray, or undefined if it never crosses it.
|
|
96
|
+
*/
|
|
97
|
+
export declare function rayExit(points: Point[], from: Point, way: Point): number | undefined;
|
|
98
|
+
/** Every distance along the line through `from` heading `way`, either direction, at which it crosses a polygon. */
|
|
99
|
+
export declare function lineCrossings(points: Point[], from: Point, way: Point): number[];
|
|
100
|
+
/** Where the line from a polygon's middle toward `target` crosses its outline: the farthest crossing, so a concave outline is met at its rim. */
|
|
101
|
+
export declare function towardOutline(points: Point[], middle: Point, target: Point): Point;
|
|
102
|
+
/**
|
|
103
|
+
* The stretch of the outline that is one side: from where the line from the
|
|
104
|
+
* middle to one corner of the box meets it, round to where the line to the
|
|
105
|
+
* next corner does. Returned in reading order, left to right along a top or
|
|
106
|
+
* bottom side and top to bottom along a left or right one.
|
|
107
|
+
*/
|
|
108
|
+
export declare function sideStretch(points: Point[], middle: Point, box: {
|
|
109
|
+
x: number;
|
|
110
|
+
y: number;
|
|
111
|
+
width: number;
|
|
112
|
+
height: number;
|
|
113
|
+
}, side: 'top' | 'bottom' | 'left' | 'right'): Point[];
|
|
114
|
+
/** The point a fraction of the way along a polyline, by length. */
|
|
115
|
+
export declare function alongPolyline(points: Point[], fraction: number): Point;
|
|
116
|
+
/** Which side of the box a point on the outline is on, by the corner rays from the middle. */
|
|
117
|
+
export declare function sideOfPoint(middle: Point, box: {
|
|
118
|
+
x: number;
|
|
119
|
+
y: number;
|
|
120
|
+
width: number;
|
|
121
|
+
height: number;
|
|
122
|
+
}, at: Point): 'top' | 'bottom' | 'left' | 'right';
|
|
123
|
+
export {};
|