@johnmorrisdotca/kyogijo-stadiums 0.4.0 → 0.6.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/CHANGELOG.md +133 -0
- package/NOTICE.md +182 -2
- package/README.md +106 -19
- package/dist/annotate.js +1 -1
- package/dist/arenas-entry.d.ts +4 -0
- package/dist/arenas-entry.js +3 -0
- package/dist/arenas.d.ts +125 -0
- package/dist/arenas.data.d.ts +2 -0
- package/dist/arenas.data.js +3763 -0
- package/dist/arenas.js +72 -0
- package/dist/athletics/describe.d.ts +8 -0
- package/dist/athletics/describe.js +41 -0
- package/dist/athletics/events.d.ts +17 -0
- package/dist/athletics/events.js +48 -0
- package/dist/athletics/facilities.d.ts +80 -0
- package/dist/athletics/facilities.js +176 -0
- package/dist/athletics/infield.d.ts +79 -0
- package/dist/athletics/infield.js +166 -0
- package/dist/athletics/layout.d.ts +13 -0
- package/dist/athletics/layout.js +98 -0
- package/dist/athletics/oval.d.ts +57 -0
- package/dist/athletics/oval.js +116 -0
- package/dist/athletics/plan.d.ts +97 -0
- package/dist/athletics/plan.js +355 -0
- package/dist/athletics/races.d.ts +102 -0
- package/dist/athletics/races.js +355 -0
- package/dist/athletics/steeplechase.d.ts +72 -0
- package/dist/athletics/steeplechase.js +196 -0
- package/dist/athletics/stencil.d.ts +13 -0
- package/dist/athletics/stencil.js +85 -0
- package/dist/athletics/track.d.ts +54 -0
- package/dist/athletics/track.js +105 -0
- package/dist/athletics/types.d.ts +77 -0
- package/dist/athletics/types.js +1 -0
- package/dist/athletics-entry.d.ts +17 -0
- package/dist/athletics-entry.js +11 -0
- package/dist/athletics.style.d.ts +16 -0
- package/dist/athletics.style.js +51 -0
- package/dist/atlas-entry.d.ts +6 -2
- package/dist/atlas-entry.js +4 -2
- package/dist/atlas.d.ts +117 -23
- package/dist/atlas.js +197 -12
- package/dist/background.js +2 -1
- package/dist/budo/describe.d.ts +13 -0
- package/dist/budo/describe.js +120 -0
- package/dist/budo/dojo.api.d.ts +64 -0
- package/dist/budo/dojo.api.js +46 -0
- package/dist/budo/dojo.d.ts +72 -0
- package/dist/budo/dojo.js +300 -0
- package/dist/budo/judo.d.ts +61 -0
- package/dist/budo/judo.js +109 -0
- package/dist/budo/karate.d.ts +29 -0
- package/dist/budo/karate.js +80 -0
- package/dist/budo/kendo.d.ts +18 -0
- package/dist/budo/kendo.js +44 -0
- package/dist/budo/kimarite.d.ts +19 -0
- package/dist/budo/kimarite.js +33 -0
- package/dist/budo/kit.d.ts +16 -0
- package/dist/budo/kit.js +24 -0
- package/dist/budo/kyudo.d.ts +28 -0
- package/dist/budo/kyudo.js +66 -0
- package/dist/budo/looks.d.ts +28 -0
- package/dist/budo/looks.js +58 -0
- package/dist/budo/parts.d.ts +32 -0
- package/dist/budo/parts.js +10 -0
- package/dist/budo/plan.d.ts +64 -0
- package/dist/budo/plan.js +139 -0
- package/dist/budo/room.d.ts +133 -0
- package/dist/budo/room.js +111 -0
- package/dist/budo/sumo.d.ts +31 -0
- package/dist/budo/sumo.js +71 -0
- package/dist/budo/tatami.d.ts +55 -0
- package/dist/budo/tatami.js +156 -0
- package/dist/budo/types.d.ts +192 -0
- package/dist/budo/types.js +2 -0
- package/dist/budo-entry.d.ts +22 -0
- package/dist/budo-entry.js +13 -0
- package/dist/budo.board.d.ts +28 -0
- package/dist/budo.board.js +81 -0
- package/dist/budo.score.d.ts +18 -0
- package/dist/budo.score.js +52 -0
- package/dist/budo.style.d.ts +6 -0
- package/dist/budo.style.js +67 -0
- package/dist/charts-entry.d.ts +6 -1
- package/dist/charts-entry.js +3 -0
- package/dist/charts.athletics.d.ts +183 -0
- package/dist/charts.athletics.js +455 -0
- package/dist/charts.baseball.js +1 -1
- package/dist/charts.curling.heat.d.ts +24 -0
- package/dist/charts.curling.heat.js +116 -0
- package/dist/charts.curling.js +14 -3
- package/dist/charts.js +4 -4
- package/dist/charts.pool.d.ts +67 -0
- package/dist/charts.pool.js +76 -0
- package/dist/charts.skating.d.ts +204 -0
- package/dist/charts.skating.js +426 -0
- package/dist/charts.soccer.js +3 -3
- package/dist/charts.types.d.ts +63 -1
- package/dist/colour.d.ts +4 -4
- package/dist/colour.js +4 -4
- package/dist/court.d.ts +85 -2
- package/dist/court.js +102 -7
- package/dist/court.more.d.ts +46 -0
- package/dist/court.more.js +219 -0
- package/dist/courts.style.d.ts +14 -2
- package/dist/courts.style.js +51 -4
- package/dist/crowd.d.ts +164 -0
- package/dist/crowd.draw.d.ts +17 -0
- package/dist/crowd.draw.js +204 -0
- package/dist/crowd.js +480 -0
- package/dist/crowd.park.d.ts +19 -0
- package/dist/crowd.park.js +153 -0
- package/dist/curling.stats.d.ts +271 -0
- package/dist/curling.stats.js +301 -0
- package/dist/draw.d.ts +16 -0
- package/dist/draw.js +462 -54
- package/dist/element-entry.d.ts +3 -1
- package/dist/element-entry.js +2 -1
- package/dist/element.d.ts +13 -2
- package/dist/element.js +79 -4
- package/dist/emblems-source.d.ts +50 -0
- package/dist/emblems-source.js +56 -0
- package/dist/eras.d.ts +3 -1
- package/dist/eras.js +8 -3
- package/dist/features.js +204 -0
- package/dist/field.data.d.ts +16 -0
- package/dist/field.data.js +50 -0
- package/dist/fields.kit.d.ts +2 -2
- package/dist/fields.types.d.ts +24 -4
- package/dist/formations.js +18 -7
- package/dist/formations.sports.d.ts +8 -0
- package/dist/formations.sports.js +251 -0
- package/dist/frames.providers.js +71 -8
- package/dist/geojson.js +3 -0
- package/dist/geometry-entry.d.ts +2 -1
- package/dist/geometry-entry.js +2 -1
- package/dist/geometry.d.ts +20 -0
- package/dist/geometry.js +78 -1
- package/dist/grounds.d.ts +4 -0
- package/dist/grounds.data.js +12 -0
- package/dist/halls.d.ts +65 -0
- package/dist/halls.js +122 -0
- package/dist/hardwood.d.ts +31 -0
- package/dist/hardwood.js +157 -0
- package/dist/heat.js +21 -13
- package/dist/heat.types.d.ts +5 -0
- package/dist/heat.zones.d.ts +4 -2
- package/dist/heat.zones.js +207 -7
- package/dist/homeside.js +24 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +18 -2
- package/dist/layers-entry.d.ts +2 -1
- package/dist/layers-entry.js +1 -0
- package/dist/layers.d.ts +2 -1
- package/dist/layers.env.d.ts +12 -1
- package/dist/layers.env.js +36 -4
- package/dist/layers.js +32 -13
- package/dist/layers.types.d.ts +9 -2
- package/dist/leagues/athletics.d.ts +63 -0
- package/dist/leagues/athletics.js +87 -0
- package/dist/leagues/budo.d.ts +196 -0
- package/dist/leagues/budo.js +105 -0
- package/dist/leagues/courts.d.ts +269 -4
- package/dist/leagues/courts.js +155 -1
- package/dist/leagues/hockey.js +41 -19
- package/dist/leagues/skating.d.ts +145 -0
- package/dist/leagues/skating.js +73 -0
- package/dist/leagues/sources.js +41 -0
- package/dist/leagues/types.d.ts +1 -1
- package/dist/leagues-entry.d.ts +4 -2
- package/dist/leagues-entry.js +2 -1
- package/dist/leagues.d.ts +17 -4
- package/dist/leagues.js +246 -5
- package/dist/lineup.codes.d.ts +23 -0
- package/dist/lineup.codes.js +122 -0
- package/dist/logo.d.ts +25 -0
- package/dist/logo.js +47 -0
- package/dist/look.d.ts +3 -3
- package/dist/look.js +39 -6
- package/dist/outline.d.ts +1 -1
- package/dist/outline.js +46 -4
- package/dist/pageant.d.ts +120 -0
- package/dist/pageant.draw.d.ts +21 -0
- package/dist/pageant.draw.js +171 -0
- package/dist/pageant.js +211 -0
- package/dist/pageant.style.d.ts +8 -0
- package/dist/pageant.style.js +42 -0
- package/dist/png.d.ts +8 -1
- package/dist/png.js +21 -1
- package/dist/pointer-entry.d.ts +2 -0
- package/dist/pointer-entry.js +2 -0
- package/dist/pointer.d.ts +113 -0
- package/dist/pointer.js +151 -0
- package/dist/pool.d.ts +176 -0
- package/dist/pool.figures.d.ts +306 -0
- package/dist/pool.figures.js +148 -0
- package/dist/pool.js +304 -0
- package/dist/pool.kit.d.ts +48 -0
- package/dist/pool.kit.js +141 -0
- package/dist/pool.labels.d.ts +20 -0
- package/dist/pool.labels.js +258 -0
- package/dist/pool.race.d.ts +65 -0
- package/dist/pool.race.js +140 -0
- package/dist/pool.replay.d.ts +46 -0
- package/dist/pool.replay.js +127 -0
- package/dist/pool.section.d.ts +13 -0
- package/dist/pool.section.js +83 -0
- package/dist/pool.style.d.ts +20 -0
- package/dist/pool.style.js +169 -0
- package/dist/pool.types.d.ts +145 -0
- package/dist/pool.types.js +3 -0
- package/dist/pool.words.d.ts +13 -0
- package/dist/pool.words.js +101 -0
- package/dist/ranges.names.js +53 -3
- package/dist/replay-entry.d.ts +3 -0
- package/dist/replay-entry.js +2 -0
- package/dist/restyle.js +1 -1
- package/dist/road.draw.js +3 -2
- package/dist/road.js +2 -1
- package/dist/road.types.d.ts +3 -0
- package/dist/rules.d.ts +138 -0
- package/dist/rules.js +511 -0
- package/dist/rules.types.d.ts +4 -0
- package/dist/rules.types.js +64 -0
- package/dist/score.d.ts +3 -0
- package/dist/score.js +93 -6
- package/dist/sheet.d.ts +3 -0
- package/dist/sheet.js +7 -3
- package/dist/situation.d.ts +135 -0
- package/dist/situation.draw.d.ts +34 -0
- package/dist/situation.draw.js +202 -0
- package/dist/situation.js +337 -0
- package/dist/situation.style.d.ts +2 -0
- package/dist/situation.style.js +45 -0
- package/dist/situation.types.d.ts +77 -0
- package/dist/situation.types.js +3 -0
- package/dist/situation.widgets.d.ts +39 -0
- package/dist/situation.widgets.js +129 -0
- package/dist/skating/describe.d.ts +7 -0
- package/dist/skating/describe.js +44 -0
- package/dist/skating/events.d.ts +24 -0
- package/dist/skating/events.js +47 -0
- package/dist/skating/figure.d.ts +24 -0
- package/dist/skating/figure.js +37 -0
- package/dist/skating/long.d.ts +54 -0
- package/dist/skating/long.js +111 -0
- package/dist/skating/parts.d.ts +43 -0
- package/dist/skating/parts.js +40 -0
- package/dist/skating/plan.d.ts +55 -0
- package/dist/skating/plan.js +197 -0
- package/dist/skating/short.d.ts +47 -0
- package/dist/skating/short.js +89 -0
- package/dist/skating/track.d.ts +66 -0
- package/dist/skating/track.js +94 -0
- package/dist/skating/types.d.ts +57 -0
- package/dist/skating/types.js +3 -0
- package/dist/skating-entry.d.ts +17 -0
- package/dist/skating-entry.js +11 -0
- package/dist/skating.style.d.ts +4 -0
- package/dist/skating.style.js +24 -0
- package/dist/strings.d.ts +470 -0
- package/dist/strings.js +674 -13
- package/dist/style.d.ts +2 -0
- package/dist/style.js +19 -2
- package/dist/surfaces/artistic.d.ts +9 -0
- package/dist/surfaces/artistic.js +94 -0
- package/dist/surfaces/athletics.d.ts +16 -0
- package/dist/surfaces/athletics.js +132 -0
- package/dist/surfaces/baseball.js +17 -0
- package/dist/surfaces/basketball.floor.d.ts +27 -0
- package/dist/surfaces/basketball.floor.js +83 -0
- package/dist/surfaces/basketball.gear.d.ts +27 -0
- package/dist/surfaces/basketball.gear.js +90 -0
- package/dist/surfaces/basketball.js +44 -22
- package/dist/surfaces/budo.d.ts +6 -0
- package/dist/surfaces/budo.js +104 -0
- package/dist/surfaces/curling.d.ts +16 -0
- package/dist/surfaces/curling.fold.d.ts +67 -0
- package/dist/surfaces/curling.fold.js +107 -0
- package/dist/surfaces/curling.js +37 -3
- package/dist/surfaces/dive.d.ts +9 -0
- package/dist/surfaces/dive.js +128 -0
- package/dist/surfaces/field.d.ts +7 -2
- package/dist/surfaces/field.js +15 -9
- package/dist/surfaces/football.js +7 -0
- package/dist/surfaces/hockey.js +4 -2
- package/dist/surfaces/net.d.ts +2 -1
- package/dist/surfaces/net.js +160 -15
- package/dist/surfaces/polo.d.ts +12 -0
- package/dist/surfaces/polo.js +159 -0
- package/dist/surfaces/pool.d.ts +27 -0
- package/dist/surfaces/pool.js +198 -0
- package/dist/surfaces/skating.d.ts +6 -0
- package/dist/surfaces/skating.js +62 -0
- package/dist/surfaces/soccer.js +2 -1
- package/dist/surfaces/surface.d.ts +76 -0
- package/dist/surfaces/venue.d.ts +15 -0
- package/dist/surfaces/venue.js +95 -0
- package/dist/target-entry.d.ts +2 -0
- package/dist/target-entry.js +2 -0
- package/dist/target.d.ts +200 -0
- package/dist/target.js +525 -0
- package/dist/team.common.d.ts +1 -1
- package/dist/team.common.js +3 -3
- package/dist/team.formation.d.ts +3 -1
- package/dist/team.formation.js +3 -3
- package/dist/team.layers.d.ts +2 -2
- package/dist/team.layers.js +4 -1
- package/dist/team.lineup.d.ts +27 -0
- package/dist/team.lineup.js +207 -0
- package/dist/team.network.js +6 -5
- package/dist/team.shape.js +5 -5
- package/dist/team.types.d.ts +40 -1
- package/dist/tenants.d.ts +77 -0
- package/dist/tenants.data.d.ts +8 -0
- package/dist/tenants.data.js +1793 -0
- package/dist/tenants.js +46 -0
- package/dist/turn-entry.d.ts +12 -0
- package/dist/turn-entry.js +7 -0
- package/dist/turn.camera.d.ts +116 -0
- package/dist/turn.camera.js +184 -0
- package/dist/turn.dom.d.ts +40 -0
- package/dist/turn.dom.js +353 -0
- package/dist/turn.kit.d.ts +86 -0
- package/dist/turn.kit.js +110 -0
- package/dist/turn.markup.d.ts +48 -0
- package/dist/turn.markup.js +108 -0
- package/dist/turn.model.d.ts +78 -0
- package/dist/turn.model.js +91 -0
- package/dist/turn.style.d.ts +5 -0
- package/dist/turn.style.js +56 -0
- package/dist/types.d.ts +221 -20
- package/dist/units.d.ts +1 -1
- package/dist/units.js +22 -1
- package/dist/uprights.board.d.ts +17 -0
- package/dist/uprights.board.js +59 -0
- package/dist/uprights.budo.d.ts +17 -0
- package/dist/uprights.budo.js +87 -0
- package/dist/uprights.d.ts +37 -0
- package/dist/uprights.fields.d.ts +32 -0
- package/dist/uprights.fields.js +172 -0
- package/dist/uprights.goal.d.ts +49 -0
- package/dist/uprights.goal.js +69 -0
- package/dist/uprights.js +169 -0
- package/dist/uprights.more.d.ts +7 -0
- package/dist/uprights.more.js +183 -0
- package/dist/uprights.net.d.ts +12 -0
- package/dist/uprights.net.js +109 -0
- package/dist/uprights.netkit.d.ts +28 -0
- package/dist/uprights.netkit.js +67 -0
- package/dist/uprights.pools.d.ts +8 -0
- package/dist/uprights.pools.js +190 -0
- package/dist/uprights.rinks.d.ts +27 -0
- package/dist/uprights.rinks.js +106 -0
- package/dist/uprights.track.d.ts +50 -0
- package/dist/uprights.track.js +246 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/zones-entry.d.ts +2 -0
- package/dist/zones-entry.js +2 -0
- package/package.json +56 -3
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { goalCage } from "./uprights.goal.js";
|
|
2
|
+
import { bar, mesh, n, plane, polygon, pole, shy, threads, wall } from "./turn.kit.js";
|
|
3
|
+
/** The boards of a rink, 42 in (NHL Rule 1.3: 40 to 48 in, 42 the ideal), the glass over them 8 ft at each end and 6 ft along the sides (Rule 1.3: not less than 6 ft). */
|
|
4
|
+
export const BOARD_HEIGHT = 3.5;
|
|
5
|
+
export const GLASS_END = 8;
|
|
6
|
+
export const GLASS_SIDE = 6;
|
|
7
|
+
/** The height of a hockey goal, 4 feet (NHL Rule 2.1). */
|
|
8
|
+
export const HOCKEY_GOAL_HEIGHT = 4;
|
|
9
|
+
/** The line round a rink's ice, as points: the straight sides and the quarter circles of its corners. */
|
|
10
|
+
export function rinkOutline(length, width, radius, steps = 6) {
|
|
11
|
+
const r = Math.min(radius, width / 2, length / 2);
|
|
12
|
+
const out = [];
|
|
13
|
+
const corner = (cx, cy, from) => {
|
|
14
|
+
for (let i = 0; i <= steps; i += 1) {
|
|
15
|
+
const a = ((from + (90 * i) / steps) * Math.PI) / 180;
|
|
16
|
+
out.push([cx + r * Math.cos(a), cy + r * Math.sin(a)]);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
// Clockwise as the page shows it: the top left corner first.
|
|
20
|
+
corner(r, r, 180);
|
|
21
|
+
corner(length - r, r, 270);
|
|
22
|
+
corner(length - r, width - r, 0);
|
|
23
|
+
corner(r, width - r, 90);
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/** The boards with the glass above them, one plane for each straight stretch of the line: the glass is 8 ft at the ends and in the corners and 6 ft along the sides. */
|
|
27
|
+
export function boardPlanes(length, width, radius, boards, thin) {
|
|
28
|
+
const points = rinkOutline(length, width, radius);
|
|
29
|
+
const planes = [];
|
|
30
|
+
const cap = Math.max(thin * 0.8, 0.12);
|
|
31
|
+
for (let i = 0; i < points.length; i += 1) {
|
|
32
|
+
const [x0, y0] = points[i];
|
|
33
|
+
const [x1, y1] = points[(i + 1) % points.length];
|
|
34
|
+
const run = Math.hypot(x1 - x0, y1 - y0);
|
|
35
|
+
if (run < 1e-6)
|
|
36
|
+
continue;
|
|
37
|
+
const along = Math.abs(y1 - y0) < 1e-6 && (Math.abs(y0) < 1e-6 || Math.abs(y0 - width) < 1e-6) && Math.min(x0, x1) >= radius - 1e-6;
|
|
38
|
+
const glass = along ? GLASS_SIDE : GLASS_END;
|
|
39
|
+
const svg = `<rect y="${n(glass)}" width="${n(run)}" height="${n(boards)}" class="u-board"/><rect width="${n(run)}" height="${n(glass)}" class="u-glass"/><rect y="${n(glass)}" width="${n(run)}" height="${n(cap)}" class="u-cap"/><rect width="${n(run)}" height="${n(cap)}" class="u-cap"/>`;
|
|
40
|
+
planes.push(wall(`board-${i}`, "glass", x0, y0, x1, y1, 0, boards + glass, svg));
|
|
41
|
+
}
|
|
42
|
+
return planes;
|
|
43
|
+
}
|
|
44
|
+
/** A rink's uprights: the boards and glass, and the two goals. `goalLine` is the distance of the goal line from the end boards. */
|
|
45
|
+
export function rinkUprights(rink, goalLine, thin, boards) {
|
|
46
|
+
const { length: L, width: W } = rink;
|
|
47
|
+
const items = [];
|
|
48
|
+
if (boards)
|
|
49
|
+
items.push({ id: "boards", kind: "boards", at: [L / 2, W / 2], height: BOARD_HEIGHT, low: BOARD_HEIGHT + GLASS_END, planes: boardPlanes(L, W, rink.cornerRadius, BOARD_HEIGHT, thin).map((p) => shy(p, [L / 2, W / 2])) });
|
|
50
|
+
const { width, depth } = rink.net;
|
|
51
|
+
for (const end of ["left", "right"]) {
|
|
52
|
+
const left = end === "left";
|
|
53
|
+
items.push(goalCage({ id: `goal-${end}`, x: left ? goalLine : L - goalLine, y: W / 2, out: left ? -1 : 1, width, height: HOCKEY_GOAL_HEIGHT, depth, top: depth * 0.55, post: Math.max(thin * 1.2, 0.17), cell: Math.max(thin * 5, 0.35), tone: "red" }));
|
|
54
|
+
}
|
|
55
|
+
return items;
|
|
56
|
+
}
|
|
57
|
+
/** The ring's upper edge is 10 ft over the floor (NBA Rule 1 Section II) and 3,050 mm in FIBA's (1.2.4). */
|
|
58
|
+
export const RIM_HEIGHT = 10;
|
|
59
|
+
export const FIBA_RIM_HEIGHT = 3.05 * 3.280839895;
|
|
60
|
+
/** The board's lower edge is 150 mm under the ring's top (FIBA 1.1.5); NBA Rule 1 gives the board's size and the ring's height but not the lower edge, which is drawn the same. */
|
|
61
|
+
export const BOARD_DROP = 0.15 * 3.280839895;
|
|
62
|
+
/** The NBA's board is 3 1/2 ft tall, FIBA's 1,050 mm. */
|
|
63
|
+
export const BOARD_TALL = 3.5;
|
|
64
|
+
export const FIBA_BOARD_TALL = 1.05 * 3.280839895;
|
|
65
|
+
/** The least distance of the support's padding behind the end line, FIBA 1.4.3 Level 1: 2,000 mm. */
|
|
66
|
+
export const SUPPORT_BEHIND = 2 * 3.280839895;
|
|
67
|
+
/** One basket: the backboard, the rim and its net, and the stanchion behind the baseline that holds them. `fiba` draws the board and the net at FIBA's size. */
|
|
68
|
+
function basket(end, court, thin, fiba) {
|
|
69
|
+
const left = end === "left";
|
|
70
|
+
const sign = left ? 1 : -1;
|
|
71
|
+
const L = court.length;
|
|
72
|
+
const cy = court.width / 2;
|
|
73
|
+
const back = left ? court.backboard.fromBaseline : L - court.backboard.fromBaseline;
|
|
74
|
+
const rimX = left ? court.basket : L - court.basket;
|
|
75
|
+
const r = court.rim;
|
|
76
|
+
const bw = court.backboard.width;
|
|
77
|
+
const tall = fiba ? FIBA_BOARD_TALL : BOARD_TALL;
|
|
78
|
+
const rimTop = fiba ? FIBA_RIM_HEIGHT : RIM_HEIGHT;
|
|
79
|
+
const bottom = rimTop - BOARD_DROP;
|
|
80
|
+
const top = bottom + tall;
|
|
81
|
+
const line = Math.max(thin * 1.8, 0.2);
|
|
82
|
+
const id = `hoop-${end}`;
|
|
83
|
+
const planes = [];
|
|
84
|
+
// The backboard: glass in a frame, with the rectangle behind the ring, its base level with the ring's top (FIBA 1.1.5: 590 by 450 mm; NBA: 24 by 18 in).
|
|
85
|
+
const targetW = fiba ? 0.59 * 3.280839895 : 2;
|
|
86
|
+
const targetH = fiba ? 0.45 * 3.280839895 : 1.5;
|
|
87
|
+
const svg = `<rect width="${n(bw)}" height="${n(tall)}" class="u-backboard"/><rect x="${n(line / 2)}" y="${n(line / 2)}" width="${n(bw - line)}" height="${n(tall - line)}" class="u-outline" stroke-width="${n(line)}" fill="none"/><rect x="${n((bw - targetW) / 2)}" y="${n(top - (rimTop + targetH))}" width="${n(targetW)}" height="${n(targetH)}" class="u-outline" stroke-width="${n(line * 0.8)}" fill="none"/>`;
|
|
88
|
+
planes.push(wall(`${id}-backboard`, "board", back, cy - bw / 2, back, cy + bw / 2, bottom, top, svg));
|
|
89
|
+
// The rim, lying flat, and the net hanging from it: two crossed trapezoids, 18 in long (NBA Rule 1 Section II; FIBA 1.3.1: 400 to 450 mm).
|
|
90
|
+
planes.push(plane(`${id}-rim`, "rim", [rimX - r, cy - r, rimTop], [2 * r, 0, 0], [0, 2 * r, 0], `<circle cx="${n(r)}" cy="${n(r)}" r="${n(r - line / 2)}" class="u-rimline" stroke-width="${n(line * 1.6)}" fill="none"/>`));
|
|
91
|
+
const drop = fiba ? 0.42 * 3.280839895 : 1.5;
|
|
92
|
+
const foot = r * 0.55;
|
|
93
|
+
const shape = polygon([[0, 0], [2 * r, 0], [r + foot, drop], [r - foot, drop]]);
|
|
94
|
+
const netSvg = `<path d="${shape}" class="u-netfill"/>${threads(mesh(2 * r, drop, 0.3), 0.3)}`;
|
|
95
|
+
planes.push(plane(`${id}-net-a`, "net", [rimX, cy - r, rimTop], [0, 2 * r, 0], [0, 0, -drop], netSvg), plane(`${id}-net-b`, "net", [rimX - r, cy, rimTop], [2 * r, 0, 0], [0, 0, -drop], netSvg));
|
|
96
|
+
// The stanchion: a padded base whose front is 2 m behind the end line, and an arm out to the back of the board.
|
|
97
|
+
const padWide = Math.max(1.1, thin * 5);
|
|
98
|
+
const stand = left ? -(SUPPORT_BEHIND + padWide / 2) : L + SUPPORT_BEHIND + padWide / 2;
|
|
99
|
+
const arm = top - 1.4;
|
|
100
|
+
planes.push(...pole(`${id}-pad`, "stanchion", stand, cy, 0, 7, padWide, "u-pad"));
|
|
101
|
+
planes.push(...pole(`${id}-mast`, "stanchion", stand, cy, 7, arm, Math.max(0.5, thin * 2.5), "u-pole"));
|
|
102
|
+
planes.push(...bar(`${id}-arm`, "stanchion", [stand, cy, arm], [back - sign * line, cy, arm], Math.max(0.4, thin * 2), "u-pole"));
|
|
103
|
+
return { id, kind: "hoop", at: [rimX, cy], height: rimTop, low: top, planes };
|
|
104
|
+
}
|
|
105
|
+
/** A court's uprights: its two baskets. */
|
|
106
|
+
export const courtUprights = (court, thin, fiba = false) => [basket("left", court, thin, fiba), basket("right", court, thin, fiba)];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type Upright } from "./turn.kit.ts";
|
|
2
|
+
import type { SurfaceOptions } from "./types.ts";
|
|
3
|
+
/** The hurdles' heights: the men's 110 m (and the covered 60 m) 1.067 m, the women's 100 m 0.838 m, the 400 m 0.914 m (Technical Rule 22); a steeplechase barrier 0.914 m (Rule 23.5). */
|
|
4
|
+
export declare const HURDLE_HEIGHT: {
|
|
5
|
+
readonly "110m-hurdles": 1.067;
|
|
6
|
+
readonly "60m-hurdles": 1.067;
|
|
7
|
+
readonly "100m-hurdles": 0.838;
|
|
8
|
+
readonly "400m-hurdles": 0.914;
|
|
9
|
+
readonly steeplechase: 0.914;
|
|
10
|
+
};
|
|
11
|
+
/** The cage's netting is at least 4 m high, and at least 6 m for the 3 m nearest the front of each side (Facilities Manual 2.4.1.3). */
|
|
12
|
+
export declare const CAGE: {
|
|
13
|
+
readonly low: 4;
|
|
14
|
+
readonly high: 6;
|
|
15
|
+
readonly highLength: 3;
|
|
16
|
+
};
|
|
17
|
+
/** The high jump's uprights are 4.02 m apart (Manual 2.3.3.3) and the pole vault's at least 5.20 m (2.3.4.3). The heights of the bars are ours. */
|
|
18
|
+
export declare const JUMPS: {
|
|
19
|
+
readonly highUprights: 4.02;
|
|
20
|
+
readonly highBar: 2;
|
|
21
|
+
readonly highPost: 2.5;
|
|
22
|
+
readonly vaultUprights: 5.2;
|
|
23
|
+
readonly vaultBar: 5;
|
|
24
|
+
readonly vaultPost: 6;
|
|
25
|
+
readonly vaultBarLength: 4.5;
|
|
26
|
+
};
|
|
27
|
+
/** The padding round a track is at least 0.80 m high and 0.30 m thick (ISU Rule 228.2). */
|
|
28
|
+
export declare const PADDING: {
|
|
29
|
+
readonly height: 0.8;
|
|
30
|
+
};
|
|
31
|
+
/** An athletics stadium's uprights, as the plan has its box. */
|
|
32
|
+
export declare function athleticsUprights(o: SurfaceOptions, thin: number): {
|
|
33
|
+
items: Upright[];
|
|
34
|
+
area: {
|
|
35
|
+
x0: number;
|
|
36
|
+
y0: number;
|
|
37
|
+
x1: number;
|
|
38
|
+
y1: number;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/** What stands at a skating rink: the padding round a long or a short track, 0.80 m high (ISU Rule 228.2); the boards of a figure skating rink, as high as a hockey rink's and with no glass over them. */
|
|
42
|
+
export declare function skatingUprights(o: SurfaceOptions, thin: number): {
|
|
43
|
+
items: Upright[];
|
|
44
|
+
area: {
|
|
45
|
+
x0: number;
|
|
46
|
+
y0: number;
|
|
47
|
+
x1: number;
|
|
48
|
+
y1: number;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// What stands in an athletics stadium and at a skating rink, in 3D: the hurdles of the races drawn and the steeplechase's barriers with the water jump's, the uprights and bars of the high jump and the
|
|
2
|
+
// pole vault, the discus and hammer cage; the padding round a long or short track and the boards of a figure skating rink. The plans are in metres in the frame of their own origin, and the drawing's
|
|
3
|
+
// frame is feet from the corner of the plan's box, so every point goes through `at`. The heights are cited in docs/sources.md ("Heights in the 3D view"): the cage's from the Track and Field
|
|
4
|
+
// Facilities Manual 2019 (2.4.1.3), the hurdles' and the barriers' from the Technical Rules (22, 23), the padding's from the ISU's Rule 228.2; the bars' heights are ours, a bar being set at the height of
|
|
5
|
+
// the competition.
|
|
6
|
+
import { athleticsPlan } from "./athletics/plan.js";
|
|
7
|
+
import { outward, ahead } from "./athletics/races.js";
|
|
8
|
+
import { HURDLE, INSIDE, OUTSIDE, scPose } from "./athletics/steeplechase.js";
|
|
9
|
+
import { laneRadius, pose } from "./athletics/track.js";
|
|
10
|
+
import { feet } from "./pool.js";
|
|
11
|
+
import { iceRadius } from "./skating/long.js";
|
|
12
|
+
import { skatingPlan } from "./skating/plan.js";
|
|
13
|
+
import { bar, mesh, n, plane, pole, shy, threads, wall } from "./turn.kit.js";
|
|
14
|
+
import { BOARD_HEIGHT } from "./uprights.rinks.js";
|
|
15
|
+
/** The hurdles' heights: the men's 110 m (and the covered 60 m) 1.067 m, the women's 100 m 0.838 m, the 400 m 0.914 m (Technical Rule 22); a steeplechase barrier 0.914 m (Rule 23.5). */
|
|
16
|
+
export const HURDLE_HEIGHT = { "110m-hurdles": 1.067, "60m-hurdles": 1.067, "100m-hurdles": 0.838, "400m-hurdles": 0.914, steeplechase: 0.914 };
|
|
17
|
+
/** A hurdle is 1.18 to 1.20 m wide (Rule 22): 1.2 m is drawn. */
|
|
18
|
+
const HURDLE_WIDTH = 1.2;
|
|
19
|
+
/** The cage's netting is at least 4 m high, and at least 6 m for the 3 m nearest the front of each side (Facilities Manual 2.4.1.3). */
|
|
20
|
+
export const CAGE = { low: 4, high: 6, highLength: 3 };
|
|
21
|
+
/** The high jump's uprights are 4.02 m apart (Manual 2.3.3.3) and the pole vault's at least 5.20 m (2.3.4.3). The heights of the bars are ours. */
|
|
22
|
+
export const JUMPS = { highUprights: 4.02, highBar: 2, highPost: 2.5, vaultUprights: 5.2, vaultBar: 5, vaultPost: 6, vaultBarLength: 4.5 };
|
|
23
|
+
/** The padding round a track is at least 0.80 m high and 0.30 m thick (ISU Rule 228.2). */
|
|
24
|
+
export const PADDING = { height: 0.8 };
|
|
25
|
+
/** A hurdle: a bar across the lane with stripes on its top, and its two uprights. */
|
|
26
|
+
function hurdlePlane(id, a, b, height, thin) {
|
|
27
|
+
const run = Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
28
|
+
const top = Math.max(feet(0.07), thin);
|
|
29
|
+
const stripes = 8;
|
|
30
|
+
let bands = "";
|
|
31
|
+
for (let i = 0; i < stripes; i += 1)
|
|
32
|
+
bands += `<rect x="${n((run * i) / stripes)}" width="${n(run / stripes)}" height="${n(top)}" class="${i % 2 === 0 ? "u-white" : "u-leg"}"/>`;
|
|
33
|
+
const side = Math.max(feet(0.04), thin * 0.8);
|
|
34
|
+
const sides = `<rect width="${n(side)}" height="${n(height)}" class="u-leg"/><rect x="${n(run - side)}" width="${n(side)}" height="${n(height)}" class="u-leg"/>`;
|
|
35
|
+
return wall(id, "wall", a[0], a[1], b[0], b[1], 0, height, `${sides}${bands}`);
|
|
36
|
+
}
|
|
37
|
+
/** The hurdles of the races a drawing marks, and the steeplechase's barriers. */
|
|
38
|
+
function hurdles(plan, at, thin) {
|
|
39
|
+
const planes = [];
|
|
40
|
+
const o = plan.oval;
|
|
41
|
+
for (const race of plan.races) {
|
|
42
|
+
if (race.hurdles === undefined)
|
|
43
|
+
continue;
|
|
44
|
+
const height = feet(HURDLE_HEIGHT[race.race.id] ?? HURDLE_HEIGHT["110m-hurdles"]);
|
|
45
|
+
for (const { lane, at: marks } of race.hurdles) {
|
|
46
|
+
marks.forEach((s, k) => {
|
|
47
|
+
const id = `hurdle-${race.race.id}-${lane}-${k + 1}`;
|
|
48
|
+
if (race.race.kind === "straight") {
|
|
49
|
+
// The lane of the straight: from its top line to the next, the 50 mm line on its right left out.
|
|
50
|
+
const top = plan.straight?.y0 ?? o.radius;
|
|
51
|
+
const sl = plan.straight?.lane ?? o.lane;
|
|
52
|
+
const y = top + (lane - 0.5) * sl - 0.025;
|
|
53
|
+
planes.push(hurdlePlane(id, at(s + 0.1, y - HURDLE_WIDTH / 2), at(s + 0.1, y + HURDLE_WIDTH / 2), height, thin));
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// On the oval: the point of the running line at that distance, and the middle of the lane across from it.
|
|
57
|
+
const run = laneRadius(o, lane);
|
|
58
|
+
const p = pose(o, run, s);
|
|
59
|
+
const [nx, ny] = outward(p.heading);
|
|
60
|
+
const rc = o.radius + (lane - 0.5) * o.lane - 0.025;
|
|
61
|
+
const c = [p.x + (rc - run) * nx, p.y + (rc - run) * ny];
|
|
62
|
+
planes.push(hurdlePlane(id, at(c[0] - (HURDLE_WIDTH / 2) * nx, c[1] - (HURDLE_WIDTH / 2) * ny), at(c[0] + (HURDLE_WIDTH / 2) * nx, c[1] + (HURDLE_WIDTH / 2) * ny), height, thin));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const items = [];
|
|
68
|
+
if (planes.length > 0)
|
|
69
|
+
items.push({ id: "hurdles", kind: "hurdles", at: [0, 0], height: Math.max(...planes.map((p) => -p.v[2])), planes });
|
|
70
|
+
if (plan.waterJump !== undefined) {
|
|
71
|
+
const barriers = [];
|
|
72
|
+
const variant = plan.waterJump;
|
|
73
|
+
const h = feet(HURDLE_HEIGHT.steeplechase);
|
|
74
|
+
(variant === "outside" ? OUTSIDE.hurdles : INSIDE.hurdles).forEach((s, i) => {
|
|
75
|
+
const p = scPose(o, variant, s);
|
|
76
|
+
const [nx, ny] = outward(p.heading);
|
|
77
|
+
const width = i === 3 ? HURDLE.pit : HURDLE.width;
|
|
78
|
+
const a = -p.innerOffset - HURDLE.inside;
|
|
79
|
+
const [x0, y0] = at(p.x + a * nx, p.y + a * ny);
|
|
80
|
+
const [x1, y1] = at(p.x + (a + width) * nx, p.y + (a + width) * ny);
|
|
81
|
+
const run = Math.hypot(x1 - x0, y1 - y0);
|
|
82
|
+
const cap = Math.max(feet(HURDLE.bar), thin);
|
|
83
|
+
barriers.push(wall(i === 3 ? "water-jump-barrier" : `steeplechase-barrier-${i + 1}`, "wall", x0, y0, x1, y1, 0, h, `<rect width="${n(run)}" height="${n(h)}" class="u-board"/><rect width="${n(run)}" height="${n(cap)}" class="u-leg"/>`));
|
|
84
|
+
if (i === 3) {
|
|
85
|
+
// The pit, 3.66 m along the run from its barrier and 3.66 m across: the water, level with the track.
|
|
86
|
+
const [fx, fy] = ahead(p.heading);
|
|
87
|
+
const lift = 0.04;
|
|
88
|
+
barriers.push(plane("water-pit", "board", [x0, y0, lift], [fx * feet(HURDLE.pit), fy * feet(HURDLE.pit), 0], [x1 - x0, y1 - y0, 0], `<rect width="${n(feet(HURDLE.pit))}" height="${n(run)}" class="u-pad"/>`));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
items.push({ id: "steeplechase", kind: "steeplechase", at: [0, 0], height: h, planes: barriers });
|
|
92
|
+
}
|
|
93
|
+
return items;
|
|
94
|
+
}
|
|
95
|
+
/** The high jump's two sets of uprights with their bars, and the pole vault's. */
|
|
96
|
+
function jumps(plan, at, thin) {
|
|
97
|
+
const items = [];
|
|
98
|
+
const posts = Math.max(feet(0.05), thin * 1.2);
|
|
99
|
+
const bars = Math.max(feet(0.03), thin * 0.7);
|
|
100
|
+
const high = [];
|
|
101
|
+
const vault = [];
|
|
102
|
+
for (const f of plan.facilities) {
|
|
103
|
+
if (f.event !== "high-jump" && f.event !== "pole-vault")
|
|
104
|
+
continue;
|
|
105
|
+
const [ux, uy] = ahead(f.heading);
|
|
106
|
+
const [vx, vy] = outward(f.heading);
|
|
107
|
+
const isHigh = f.event === "high-jump";
|
|
108
|
+
const half = (isHigh ? JUMPS.highUprights : JUMPS.vaultUprights) / 2;
|
|
109
|
+
// The pole vault's uprights stand 0.1 m beyond the middle of the stop board (the drawing's); the high jump's on the take-off line.
|
|
110
|
+
const along = isHigh ? 0 : 0.1;
|
|
111
|
+
const a = at(f.x + along * ux - half * vx, f.y + along * uy - half * vy);
|
|
112
|
+
const b = at(f.x + along * ux + half * vx, f.y + along * uy + half * vy);
|
|
113
|
+
const top = feet(isHigh ? JUMPS.highPost : JUMPS.vaultPost);
|
|
114
|
+
const barZ = feet(isHigh ? JUMPS.highBar : JUMPS.vaultBar);
|
|
115
|
+
const out = isHigh ? high : vault;
|
|
116
|
+
out.push(...pole(`${f.id}-upright-a`, "post", a[0], a[1], 0, top, posts, "u-pole"), ...pole(`${f.id}-upright-b`, "post", b[0], b[1], 0, top, posts, "u-pole"));
|
|
117
|
+
// The high jump's bar runs from upright to upright; the vault's rests on supports between them and is 4.5 m long.
|
|
118
|
+
if (isHigh)
|
|
119
|
+
out.push(...bar(`${f.id}-bar`, "post", [a[0], a[1], barZ], [b[0], b[1], barZ], bars, "u-white"));
|
|
120
|
+
else {
|
|
121
|
+
const m = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
|
|
122
|
+
const d = Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
123
|
+
const k = (feet(JUMPS.vaultBarLength) / 2) / d;
|
|
124
|
+
out.push(...bar(`${f.id}-bar`, "post", [m[0] - (b[0] - a[0]) * k, m[1] - (b[1] - a[1]) * k, barZ], [m[0] + (b[0] - a[0]) * k, m[1] + (b[1] - a[1]) * k, barZ], bars, "u-white"));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (high.length > 0)
|
|
128
|
+
items.push({ id: "high-jump", kind: "high-jump", at: [0, 0], height: feet(JUMPS.highBar), planes: high });
|
|
129
|
+
if (vault.length > 0)
|
|
130
|
+
items.push({ id: "pole-vault", kind: "pole-vault", at: [0, 0], height: feet(JUMPS.vaultBar), planes: vault });
|
|
131
|
+
return items;
|
|
132
|
+
}
|
|
133
|
+
/** The discus and hammer cage: netting 4 m high, 6 m for the 3 m nearest the front of each side, along the plan's U (the mouth 6 m wide 7 m in front of the circle's centre). */
|
|
134
|
+
function cage(plan, at, thin) {
|
|
135
|
+
const seen = new Set();
|
|
136
|
+
const planes = [];
|
|
137
|
+
const cell = Math.max(feet(0.5), thin * 4);
|
|
138
|
+
const netting = (id, a, b, z, h) => {
|
|
139
|
+
const [x0, y0] = at(a[0], a[1]);
|
|
140
|
+
const [x1, y1] = at(b[0], b[1]);
|
|
141
|
+
const run = Math.hypot(x1 - x0, y1 - y0);
|
|
142
|
+
if (run <= 0)
|
|
143
|
+
return;
|
|
144
|
+
planes.push(wall(id, "wall", x0, y0, x1, y1, z, z + h, `<rect width="${n(run)}" height="${n(h)}" class="u-netfill"/>${threads(mesh(run, h, cell), cell)}<rect width="${n(run)}" height="${n(Math.max(thin * 0.5, 0.1))}" class="u-cap"/>`));
|
|
145
|
+
};
|
|
146
|
+
for (const f of plan.facilities) {
|
|
147
|
+
if (f.event !== "discus-throw" && f.event !== "hammer-throw")
|
|
148
|
+
continue;
|
|
149
|
+
const key = `${f.x.toFixed(2)},${f.y.toFixed(2)}`;
|
|
150
|
+
if (seen.has(key))
|
|
151
|
+
continue;
|
|
152
|
+
seen.add(key);
|
|
153
|
+
const [ux, uy] = ahead(f.heading);
|
|
154
|
+
const [vx, vy] = outward(f.heading);
|
|
155
|
+
const pt = (u, v) => [f.x + u * ux + v * vx, f.y + u * uy + v * vy];
|
|
156
|
+
// The sides, from the mouth back to the circle's level: the first 3 m of each at 6 m, the rest at 4 m. The line is the plan's own: (7, ±3) to (0, ±4.4).
|
|
157
|
+
for (const side of [-1, 1]) {
|
|
158
|
+
const mouth = pt(7, side * 3);
|
|
159
|
+
const back = pt(0, side * 4.4);
|
|
160
|
+
const length = Math.hypot(back[0] - mouth[0], back[1] - mouth[1]);
|
|
161
|
+
const t = CAGE.highLength / length;
|
|
162
|
+
const mid = [mouth[0] + (back[0] - mouth[0]) * t, mouth[1] + (back[1] - mouth[1]) * t];
|
|
163
|
+
netting(`cage-side-${side < 0 ? "a" : "b"}-front`, mouth, mid, 0, feet(CAGE.high));
|
|
164
|
+
netting(`cage-side-${side < 0 ? "a" : "b"}-back`, mid, back, 0, feet(CAGE.low));
|
|
165
|
+
}
|
|
166
|
+
// The rear: the half circle of 4.4 m about the centre, behind it, in eight chords.
|
|
167
|
+
const steps = 8;
|
|
168
|
+
for (let i = 0; i < steps; i += 1) {
|
|
169
|
+
const p0 = (Math.PI * i) / steps;
|
|
170
|
+
const p1 = (Math.PI * (i + 1)) / steps;
|
|
171
|
+
const g = (p) => pt(-4.4 * Math.sin(p), -4.4 * Math.cos(p));
|
|
172
|
+
netting(`cage-rear-${i + 1}`, g(p0), g(p1), 0, feet(CAGE.low));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return planes.length === 0 ? [] : [{ id: "cage", kind: "cage", at: [0, 0], height: feet(CAGE.high), planes }];
|
|
176
|
+
}
|
|
177
|
+
/** An athletics stadium's uprights, as the plan has its box. */
|
|
178
|
+
export function athleticsUprights(o, thin) {
|
|
179
|
+
const plan = athleticsPlan({ ...o, detail: o.detail });
|
|
180
|
+
const at = (x, y) => [feet(x - plan.box.x0), feet(y - plan.box.y0)];
|
|
181
|
+
return {
|
|
182
|
+
items: [...hurdles(plan, at, thin), ...jumps(plan, at, thin), ...cage(plan, at, thin)],
|
|
183
|
+
area: { x0: 0, y0: 0, x1: feet(plan.box.x1 - plan.box.x0), y1: feet(plan.box.y1 - plan.box.y0) },
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/** The walls of a closed outline of points, as planes of `height`: each segment is a wall whose inner face is drawn, giving way to the eye. */
|
|
187
|
+
function walls(id, points, height, side, top, thin, centre) {
|
|
188
|
+
const planes = [];
|
|
189
|
+
for (let i = 0; i < points.length; i += 1) {
|
|
190
|
+
const [x0, y0] = points[i];
|
|
191
|
+
const [x1, y1] = points[(i + 1) % points.length];
|
|
192
|
+
const run = Math.hypot(x1 - x0, y1 - y0);
|
|
193
|
+
if (run < 1e-6)
|
|
194
|
+
continue;
|
|
195
|
+
const cap = Math.max(thin * 0.8, 0.1);
|
|
196
|
+
planes.push(shy(wall(`${id}-${i}`, "wall", x0, y0, x1, y1, 0, height, `<rect width="${n(run)}" height="${n(height)}" class="${side}"/><rect width="${n(run)}" height="${n(cap)}" class="${top}"/>`), centre));
|
|
197
|
+
}
|
|
198
|
+
return planes;
|
|
199
|
+
}
|
|
200
|
+
/** A stadium's outline (two straights of `f` between the centres of two half circles of radius `r`) as points about the origin, in metres. */
|
|
201
|
+
function stadiumPoints(f, r, steps = 14) {
|
|
202
|
+
const out = [[-f / 2, -r]];
|
|
203
|
+
for (let i = 0; i <= steps; i += 1) {
|
|
204
|
+
const a = (Math.PI * i) / steps;
|
|
205
|
+
out.push([f / 2 + r * Math.sin(a), -r * Math.cos(a)]);
|
|
206
|
+
}
|
|
207
|
+
for (let i = 0; i <= steps; i += 1) {
|
|
208
|
+
const a = (Math.PI * i) / steps;
|
|
209
|
+
out.push([-f / 2 - r * Math.sin(a), r * Math.cos(a)]);
|
|
210
|
+
}
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
/** A rounded rectangle's outline, half sizes `hx`, `hy` and corner radius `k`, as points about the origin, in metres. */
|
|
214
|
+
function roundedPoints(hx, hy, k, steps = 6) {
|
|
215
|
+
const out = [];
|
|
216
|
+
const corners = [[hx - k, -hy + k, -Math.PI / 2], [hx - k, hy - k, 0], [-hx + k, hy - k, Math.PI / 2], [-hx + k, -hy + k, Math.PI]];
|
|
217
|
+
for (const [cx, cy, a0] of corners)
|
|
218
|
+
for (let i = 0; i <= steps; i += 1)
|
|
219
|
+
out.push([cx + k * Math.cos(a0 + ((Math.PI / 2) * i) / steps), cy + k * Math.sin(a0 + ((Math.PI / 2) * i) / steps)]);
|
|
220
|
+
return out;
|
|
221
|
+
}
|
|
222
|
+
/** What stands at a skating rink: the padding round a long or a short track, 0.80 m high (ISU Rule 228.2); the boards of a figure skating rink, as high as a hockey rink's and with no glass over them. */
|
|
223
|
+
export function skatingUprights(o, thin) {
|
|
224
|
+
const plan = skatingPlan({ ...o, detail: o.detail });
|
|
225
|
+
const at = (p) => [feet(p[0] - plan.box.x0), feet(p[1] - plan.box.y0)];
|
|
226
|
+
const area = { x0: 0, y0: 0, x1: feet(plan.box.x1 - plan.box.x0), y1: feet(plan.box.y1 - plan.box.y0) };
|
|
227
|
+
const centre = at([0, 0]);
|
|
228
|
+
const items = [];
|
|
229
|
+
const style = o.skating;
|
|
230
|
+
const padding = style?.padding !== false;
|
|
231
|
+
if (plan.oval !== undefined && padding) {
|
|
232
|
+
const R = iceRadius(plan.oval);
|
|
233
|
+
const points = stadiumPoints(plan.oval.straight, R).map(at);
|
|
234
|
+
items.push({ id: "padding", kind: "padding", at: centre, height: feet(PADDING.height), planes: walls("padding", points, feet(PADDING.height), "u-pad", "u-cap", thin, centre) });
|
|
235
|
+
}
|
|
236
|
+
else if (plan.short !== undefined && padding) {
|
|
237
|
+
const points = roundedPoints(plan.short.length / 2, plan.short.width / 2, 8.5).map(at);
|
|
238
|
+
items.push({ id: "padding", kind: "padding", at: centre, height: feet(PADDING.height), planes: walls("padding", points, feet(PADDING.height), "u-pad", "u-cap", thin, centre) });
|
|
239
|
+
}
|
|
240
|
+
else if (plan.rink !== undefined) {
|
|
241
|
+
const fig = plan.figures;
|
|
242
|
+
const points = roundedPoints(plan.rink.length / 2, plan.rink.width / 2, fig.corner ?? 8.5).map(at);
|
|
243
|
+
items.push({ id: "rink-boards", kind: "rink-boards", at: centre, height: BOARD_HEIGHT, planes: walls("board", points, BOARD_HEIGHT, "u-board", "u-cap", thin, centre) });
|
|
244
|
+
}
|
|
245
|
+
return { items, area };
|
|
246
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The package's version: the same as package.json's, and a test holds them to each other. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.6.0";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The package's version: the same as package.json's, and a test holds them to each other. */
|
|
2
|
-
export const VERSION = "0.
|
|
2
|
+
export const VERSION = "0.6.0";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { PARKS_WITHOUT_WALL_HEIGHTS, RULE_IDS, betweenHashes, homeRun, inCrease, inPaint, inPenaltyArea, inRedZone, inRestrictedArea, inSixYardBox, inSlot, isFair, isHomeRun, isThreePointer, onWarningTrack, overWall, wallHeightAt, zoneAt, zoneAtSurface, zoneName, zoneResolver } from "./rules.ts";
|
|
2
|
+
export type { HomeRunOptions, HomeRunVerdict, PlaceLike, RuleId, ZoneAnswer, ZoneOptions } from "./rules.ts";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// The rulebook as code: where a point lies on a surface in the sport's own terms (the zone, the area in it, every other area that holds), and the yes-or-no questions a coach asks.
|
|
2
|
+
export { PARKS_WITHOUT_WALL_HEIGHTS, RULE_IDS, betweenHashes, homeRun, inCrease, inPaint, inPenaltyArea, inRedZone, inRestrictedArea, inSixYardBox, inSlot, isFair, isHomeRun, isThreePointer, onWarningTrack, overWall, wallHeightAt, zoneAt, zoneAtSurface, zoneName, zoneResolver } from "./rules.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/kyogijo-stadiums",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Kyogijo Stadiums 競技場, sports surfaces as SVG, drawn to scale from the rulebooks: NFL, CFL and IFAF football fields, an NHL rink, an NBA court
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Kyogijo Stadiums 競技場, 39 sports' surfaces as SVG, drawn to scale from the rulebooks: NFL, CFL and IFAF football fields, an NHL rink, an NBA court, MLB ballparks, soccer pitches, curling sheets, athletics stadiums, speed skating, short track and figure skating rinks, swimming pools, water polo fields, diving wells, artistic swimming areas, and the courts and fields of tennis, volleyball (indoor, beach and sitting), badminton, pickleball, table tennis, padel, squash, racquetball, sepak takraw, teqball, roundnet, netball, lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, and the budo of judo, karate, kendo, sumo and kyudo with a dojo of tatami laid as real units, with each team's name and logo on its side and the score in the middle, stands and a crowd, a pageant of flags, and a 3D view. Light and dark, accessible, a compact badge for lists, a helper for React and a custom element. Zero dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sports",
|
|
7
7
|
"scoreboard",
|
|
@@ -43,7 +43,14 @@
|
|
|
43
43
|
"zero-dependencies",
|
|
44
44
|
"browser",
|
|
45
45
|
"node",
|
|
46
|
-
"itsutsu"
|
|
46
|
+
"itsutsu",
|
|
47
|
+
"judo",
|
|
48
|
+
"karate",
|
|
49
|
+
"kendo",
|
|
50
|
+
"sumo",
|
|
51
|
+
"kyudo",
|
|
52
|
+
"dojo",
|
|
53
|
+
"tatami"
|
|
47
54
|
],
|
|
48
55
|
"homepage": "https://johnmorrisdotca.github.io/kyogijo-stadiums/",
|
|
49
56
|
"repository": {
|
|
@@ -114,6 +121,11 @@
|
|
|
114
121
|
"import": "./dist/eras-entry.js",
|
|
115
122
|
"default": "./dist/eras-entry.js"
|
|
116
123
|
},
|
|
124
|
+
"./arenas": {
|
|
125
|
+
"types": "./dist/arenas-entry.d.ts",
|
|
126
|
+
"import": "./dist/arenas-entry.js",
|
|
127
|
+
"default": "./dist/arenas-entry.js"
|
|
128
|
+
},
|
|
117
129
|
"./grounds": {
|
|
118
130
|
"types": "./dist/grounds-entry.d.ts",
|
|
119
131
|
"import": "./dist/grounds-entry.js",
|
|
@@ -129,6 +141,21 @@
|
|
|
129
141
|
"import": "./dist/atlas-entry.js",
|
|
130
142
|
"default": "./dist/atlas-entry.js"
|
|
131
143
|
},
|
|
144
|
+
"./athletics": {
|
|
145
|
+
"types": "./dist/athletics-entry.d.ts",
|
|
146
|
+
"import": "./dist/athletics-entry.js",
|
|
147
|
+
"default": "./dist/athletics-entry.js"
|
|
148
|
+
},
|
|
149
|
+
"./skating": {
|
|
150
|
+
"types": "./dist/skating-entry.d.ts",
|
|
151
|
+
"import": "./dist/skating-entry.js",
|
|
152
|
+
"default": "./dist/skating-entry.js"
|
|
153
|
+
},
|
|
154
|
+
"./budo": {
|
|
155
|
+
"types": "./dist/budo-entry.d.ts",
|
|
156
|
+
"import": "./dist/budo-entry.js",
|
|
157
|
+
"default": "./dist/budo-entry.js"
|
|
158
|
+
},
|
|
132
159
|
"./charts": {
|
|
133
160
|
"types": "./dist/charts-entry.d.ts",
|
|
134
161
|
"import": "./dist/charts-entry.js",
|
|
@@ -174,6 +201,26 @@
|
|
|
174
201
|
"import": "./dist/png-entry.js",
|
|
175
202
|
"default": "./dist/png-entry.js"
|
|
176
203
|
},
|
|
204
|
+
"./zones": {
|
|
205
|
+
"types": "./dist/zones-entry.d.ts",
|
|
206
|
+
"import": "./dist/zones-entry.js",
|
|
207
|
+
"default": "./dist/zones-entry.js"
|
|
208
|
+
},
|
|
209
|
+
"./pointer": {
|
|
210
|
+
"types": "./dist/pointer-entry.d.ts",
|
|
211
|
+
"import": "./dist/pointer-entry.js",
|
|
212
|
+
"default": "./dist/pointer-entry.js"
|
|
213
|
+
},
|
|
214
|
+
"./target": {
|
|
215
|
+
"types": "./dist/target-entry.d.ts",
|
|
216
|
+
"import": "./dist/target-entry.js",
|
|
217
|
+
"default": "./dist/target-entry.js"
|
|
218
|
+
},
|
|
219
|
+
"./turn": {
|
|
220
|
+
"types": "./dist/turn-entry.d.ts",
|
|
221
|
+
"import": "./dist/turn-entry.js",
|
|
222
|
+
"default": "./dist/turn-entry.js"
|
|
223
|
+
},
|
|
177
224
|
"./element/define": {
|
|
178
225
|
"types": "./dist/element-define.d.ts",
|
|
179
226
|
"import": "./dist/element-define.js",
|
|
@@ -213,15 +260,21 @@
|
|
|
213
260
|
"test:readme": "pnpm build && node scripts/check-readme-examples.mjs",
|
|
214
261
|
"docs:make": "node scripts/docs.mjs",
|
|
215
262
|
"parks": "node scripts/build-parks.mjs",
|
|
263
|
+
"arenas": "node scripts/build-arenas.mjs",
|
|
264
|
+
"arenas:fetch": "node scripts/fetch-arenas.mjs",
|
|
265
|
+
"arenas:check": "node scripts/check-arenas.mjs",
|
|
216
266
|
"grounds": "node scripts/build-grounds.mjs",
|
|
217
267
|
"grounds:check": "node scripts/check-grounds.mjs",
|
|
218
268
|
"parks:coordinates": "node scripts/fetch-park-coordinates.mjs",
|
|
219
269
|
"names:fetch": "node scripts/fetch-names.mjs",
|
|
270
|
+
"tenants": "node scripts/build-tenants.mjs",
|
|
271
|
+
"tenants:fetch": "node scripts/fetch-tenants.mjs",
|
|
220
272
|
"parks:check": "node scripts/check-parks.mjs"
|
|
221
273
|
},
|
|
222
274
|
"devDependencies": {
|
|
223
275
|
"@eslint/js": "^9.0.0",
|
|
224
276
|
"@johnmorrisdotca/chizu": "1.4.0",
|
|
277
|
+
"@johnmorrisdotca/dougu-sports": "0.2.0",
|
|
225
278
|
"@playwright/test": "^1.63.0",
|
|
226
279
|
"eslint": "^9.0.0",
|
|
227
280
|
"marked": "^18.1.1",
|