@johnmorrisdotca/kyogijo-stadiums 0.40.2 → 0.44.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 +72 -0
- package/NOTICE.md +22 -0
- package/README.md +1 -3
- package/dist/cityctx-entry.d.ts +3 -0
- package/dist/cityctx-entry.js +3 -0
- package/dist/cityctx.d.ts +19 -0
- package/dist/cityctx.data.d.ts +11 -0
- package/dist/cityctx.data.js +7139 -0
- package/dist/cityctx.js +34 -0
- package/dist/context.d.ts +175 -0
- package/dist/context.js +369 -0
- package/dist/crowd.d.ts +9 -0
- package/dist/district-entry.d.ts +16 -1
- package/dist/district-entry.js +9 -0
- package/dist/district.d.ts +99 -4
- package/dist/district.dom.d.ts +31 -0
- package/dist/district.dom.js +52 -0
- package/dist/district.js +103 -25
- package/dist/district.turn.js +89 -19
- package/dist/gates.d.ts +56 -0
- package/dist/gates.js +95 -0
- package/dist/halls.d.ts +2 -0
- package/dist/halls.js +1 -1
- package/dist/kodokan.d.ts +116 -0
- package/dist/kodokan.data.d.ts +61 -0
- package/dist/kodokan.data.js +20 -0
- package/dist/kodokan.js +92 -0
- package/dist/osm-entry.d.ts +2 -0
- package/dist/osm-entry.js +2 -0
- package/dist/osm.context.data.d.ts +10 -0
- package/dist/osm.context.data.js +1107 -0
- package/dist/outside.d.ts +43 -0
- package/dist/outside.dom.d.ts +44 -0
- package/dist/outside.dom.js +203 -0
- package/dist/outside.js +227 -0
- package/dist/outside.paint.d.ts +57 -0
- package/dist/outside.paint.js +88 -0
- package/dist/plateau-entry.d.ts +3 -0
- package/dist/plateau-entry.js +3 -0
- package/dist/plateau.credit.d.ts +5 -0
- package/dist/plateau.credit.js +7 -0
- package/dist/plateau.data.d.ts +7 -0
- package/dist/plateau.data.js +757 -0
- package/dist/stadiums.d.ts +14 -0
- package/dist/stadiums.data.js +2 -1
- package/dist/stadiums.js +2 -0
- package/dist/strings.d.ts +3 -1
- package/dist/strings.js +4 -4
- package/dist/turn.dom.d.ts +10 -0
- package/dist/turn.dom.js +21 -0
- package/dist/turn.kit.d.ts +12 -3
- package/dist/turn.kit.js +7 -0
- package/dist/turn.markup.js +15 -3
- package/dist/turn.model.d.ts +3 -0
- package/dist/turn.style.js +20 -3
- package/dist/venue.real.d.ts +22 -1
- package/dist/venue.real.js +76 -7
- package/dist/venues.d.ts +9 -1
- package/dist/venues.data.js +2 -1
- package/dist/venues.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/walk.d.ts +56 -0
- package/dist/walk.data.d.ts +4 -0
- package/dist/walk.data.js +1295 -0
- package/dist/walk.js +120 -0
- package/package.json +25 -1
package/dist/district.turn.js
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
// (`buildTurn`: the stands, the walls and the roof, the goals and posts of its field), its planes are turned about the middle of its surface and moved to where the plan puts it, and the floor is the district's flat
|
|
3
3
|
// plan drawn with each venue's building only. The model it makes is a `TurnModel`, so the camera, the controls, the pointer, the auto-turn and the steady fit of every other 3D view are this one's; its
|
|
4
4
|
// buildings are stacked building by building (`Plane.group`), the far one first, so that a roof never shows through a nearer building.
|
|
5
|
-
import { describeDistrict, districtId, drawDistrict, drawMember, planDistrict, surfaceCentre } from "./district.js";
|
|
6
|
-
import {
|
|
5
|
+
import { describeDistrict, districtId, drawDistrict, drawMember, nestedDrawing, planDistrict, surfaceCentre } from "./district.js";
|
|
6
|
+
import { blockPlanes, contextUprights, shellBlock, slabPlanes } from "./context.js";
|
|
7
|
+
import { dojo } from "./budo/dojo.api.js";
|
|
8
|
+
import { KODOKAN_FLOORS, KODOKAN_GALLERY_LEVEL } from "./kodokan.js";
|
|
9
|
+
import { APART, n, plane } from "./turn.kit.js";
|
|
7
10
|
import { TURN_PRESETS, wrap } from "./turn.camera.js";
|
|
8
11
|
import { mountTurn } from "./turn.dom.js";
|
|
9
12
|
import { turnMarkupOf } from "./turn.markup.js";
|
|
@@ -11,6 +14,7 @@ import { buildTurn, lightingOf, openingView, sceneBox, WORLD_PX } from "./turn.m
|
|
|
11
14
|
import { planesOf } from "./uprights.js";
|
|
12
15
|
import { FEET_PER_METRE } from "./geometry.js";
|
|
13
16
|
import { hullOf } from "./venues.geo.js";
|
|
17
|
+
import { hasOutside, outsideCrowd, outsideLevelOf } from "./outside.js";
|
|
14
18
|
/** The four viewpoints of a district, turned with the map: the main camera looks from the south over the district (north at the top of the page), the end-on view from the west and the low corner from the south-west. */
|
|
15
19
|
export function districtPresets(plan) {
|
|
16
20
|
const turn = plan.turn;
|
|
@@ -27,7 +31,7 @@ const rot = ([x, y], degrees) => {
|
|
|
27
31
|
return [x * Math.cos(a) - y * Math.sin(a), x * Math.sin(a) + y * Math.cos(a)];
|
|
28
32
|
};
|
|
29
33
|
/** A plane of a venue's own frame (its surface's middle at `centre`) put in the district's: turned by the venue's angle about that middle and moved to where the plan puts it. */
|
|
30
|
-
function placeInDistrict(p, placed, centre, prefix, group) {
|
|
34
|
+
function placeInDistrict(p, placed, centre, prefix, group, lift = 0) {
|
|
31
35
|
const at = (x, y) => {
|
|
32
36
|
const [rx, ry] = rot([x - centre[0], y - centre[1]], placed.angle);
|
|
33
37
|
return [rx + placed.at[0], ry + placed.at[1]];
|
|
@@ -36,7 +40,7 @@ function placeInDistrict(p, placed, centre, prefix, group) {
|
|
|
36
40
|
const [ox, oy] = at(p.o[0], p.o[1]);
|
|
37
41
|
const [ux, uy] = dir(p.u[0], p.u[1]);
|
|
38
42
|
const [vx, vy] = dir(p.v[0], p.v[1]);
|
|
39
|
-
const moved = { ...p, id: `${prefix}${p.id}`, o: [ox, oy, p.o[2]], u: [ux, uy, p.u[2]], v: [vx, vy, p.v[2]], group };
|
|
43
|
+
const moved = { ...p, id: `${prefix}${p.id}`, o: [ox, oy, p.o[2] + lift], u: [ux, uy, p.u[2]], v: [vx, vy, p.v[2]], group };
|
|
40
44
|
if (p.shy !== undefined)
|
|
41
45
|
moved.shy = dir(p.shy[0], p.shy[1]);
|
|
42
46
|
if (p.crop === true) {
|
|
@@ -72,24 +76,88 @@ export function buildDistrictTurn(options, settings = {}) {
|
|
|
72
76
|
let crowdStyle = "";
|
|
73
77
|
plan.members.forEach((placed, i) => {
|
|
74
78
|
const member = placed.member;
|
|
75
|
-
const memberId = `${id}-m${i}`;
|
|
76
|
-
// Each venue is built as its own 3D view is, with the crowd drawn without its seats on its floor and the stands raised.
|
|
77
|
-
const model = buildTurn({ ...member.options, language, ...(options.theme === undefined ? {} : { theme: options.theme }), id: `${base}-m${i}` }, { ...settings, id: memberId, venue: { roof: true, ...(typeof settings.venue === "object" ? settings.venue : {}) }, preset: undefined, view: undefined });
|
|
78
|
-
const centre = surfaceCentre(member.options);
|
|
79
79
|
const prefix = `m${i}-`;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
// A venue may have several surfaces (the rooms of a floor): each is built as its own 3D view is, with the crowd drawn without its seats on its floor and the stands raised, and put where the plan puts it, in the venue's one group.
|
|
81
|
+
placed.parts.forEach((pp, j) => {
|
|
82
|
+
const part = pp.part;
|
|
83
|
+
const tag = j === 0 ? "" : `p${j}`;
|
|
84
|
+
const memberId = `${id}-m${i}${tag}`;
|
|
85
|
+
const model = buildTurn({ ...part.options, language, ...(options.theme === undefined ? {} : { theme: options.theme }), id: `${base}-m${i}${tag}` }, { ...settings, id: memberId, venue: { roof: true, ...(typeof settings.venue === "object" ? settings.venue : {}) }, preset: undefined, view: undefined });
|
|
86
|
+
const centre = surfaceCentre(part.options);
|
|
87
|
+
const pfx = `m${i}${tag}-`;
|
|
88
|
+
// A surface on an upper floor (the Kodokan's dojos) stands that high over the ground, on a floor drawn in the air; the ground under it is left bare.
|
|
89
|
+
const lift = part.elevation ?? 0;
|
|
90
|
+
// Which part of a room is drawn: what stands below the gallery's level, or what stands above it.
|
|
91
|
+
const lowest = (p) => Math.min(p.o[2], p.o[2] + p.u[2], p.o[2] + p.v[2], p.o[2] + p.u[2] + p.v[2]);
|
|
92
|
+
const shown = (p) => part.show === undefined || (part.show === "gallery") === (lowest(p) >= KODOKAN_GALLERY_LEVEL - 1e-6);
|
|
93
|
+
for (const item of model.uprights.items) {
|
|
94
|
+
const planes = item.planes.filter((p) => p.kind !== "ground" && shown(p)).map((p) => placeInDistrict(p, pp, centre, pfx, i, lift));
|
|
95
|
+
if (planes.length > 0) {
|
|
96
|
+
const [ax, ay] = item.at;
|
|
97
|
+
const [rx, ry] = rot([ax - centre[0], ay - centre[1]], pp.angle);
|
|
98
|
+
items.push({ ...item, id: `${pfx}${item.id}`, at: [rx + pp.at[0], ry + pp.at[1]], height: item.height + lift, planes });
|
|
99
|
+
}
|
|
86
100
|
}
|
|
101
|
+
if (lift > 0 && part.show !== "gallery") {
|
|
102
|
+
const { markup, box, styles } = nestedDrawing(drawMember(member, { ...options, id: base }, i, base, { floor: true }, j));
|
|
103
|
+
for (const block of styles)
|
|
104
|
+
if (!defs.includes(block))
|
|
105
|
+
defs.push(block);
|
|
106
|
+
const floor = plane("floor", "floor", [box.x, box.y, 0], [box.w, 0, 0], [0, box.h, 0], `<g transform="translate(${n(-box.x)} ${n(-box.y)})">${markup}</g>`);
|
|
107
|
+
items.push({ id: `${pfx}floor`, kind: "deck", at: pp.at, height: lift, planes: [placeInDistrict(floor, pp, centre, pfx, i, lift)] });
|
|
108
|
+
// The room's floor is a slab too, with an edge all round (the building's own floors do that for a chosen floor): its mats' rectangle and a hand's width more.
|
|
109
|
+
const spec = part.options.dojo;
|
|
110
|
+
if (member.plate === undefined && spec !== undefined && member.slabThickness !== undefined) {
|
|
111
|
+
const room = dojo(spec);
|
|
112
|
+
const m = 0.12 * FEET_PER_METRE;
|
|
113
|
+
const [w, l] = [room.width * FEET_PER_METRE, room.length * FEET_PER_METRE];
|
|
114
|
+
const corners = [[-m, -m], [w + m, -m], [w + m, l + m], [-m, l + m]].map(([x, y]) => {
|
|
115
|
+
const [rx, ry] = rot([x - centre[0], y - centre[1]], pp.angle);
|
|
116
|
+
return [rx + pp.at[0], ry + pp.at[1]];
|
|
117
|
+
});
|
|
118
|
+
const pixels = 1000 / Math.max(plan.view.w, plan.view.h);
|
|
119
|
+
const thick = Math.min(Math.max(member.slabThickness * FEET_PER_METRE, 10 / pixels), ((member.shell?.height ?? 60) / (member.shell?.storeys ?? 8)) * 0.5);
|
|
120
|
+
items.push({ id: `${pfx}slab`, kind: "deck", at: pp.at, height: lift, planes: slabPlanes(corners, lift, thick, { top: `${pfx}slab-top`, side: `${pfx}slab-s` }, "plain").map((p) => ({ ...p, group: i })) });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (model.defs !== "")
|
|
124
|
+
defs.push(model.defs);
|
|
125
|
+
if (crowdStyle === "" && model.crowdStyle !== "")
|
|
126
|
+
crowdStyle = model.crowdStyle;
|
|
127
|
+
});
|
|
128
|
+
// The building it stands in: see-through (its walls give way to the eye) or solid, in the venue's group so that it is stacked with it.
|
|
129
|
+
if (member.shell !== undefined && options.building !== "none") {
|
|
130
|
+
// What is seen through its walls: the middle of the rooms in it (the building's own middle where a floor has none).
|
|
131
|
+
const inside = placed.parts.length === 0 ? placed.at : [placed.parts.reduce((s, q) => s + q.at[0], 0) / placed.parts.length, placed.parts.reduce((s, q) => s + q.at[1], 0) / placed.parts.length];
|
|
132
|
+
const block = shellBlock(member.key, placed.footprint, member.shell.height, options.building === "solid" ? undefined : inside);
|
|
133
|
+
const planes = blockPlanes(block, `${prefix}shell-`).map((p) => ({ ...p, group: i }));
|
|
134
|
+
items.push({ id: `${prefix}shell`, kind: "blocks", at: placed.at, height: member.shell.height, planes });
|
|
135
|
+
}
|
|
136
|
+
// The floors of the building as slabs with an edge: the one chosen is picked out (its plate, with its name over it), the others are faint. A slab is as thick as the venue says and never thinner than ten pixels at the page's own size.
|
|
137
|
+
if (member.slabs !== undefined && options.building !== "none") {
|
|
138
|
+
const pixels = 1000 / Math.max(plan.view.w, plan.view.h);
|
|
139
|
+
const thick = Math.min(Math.max((member.slabThickness ?? 0.6) * FEET_PER_METRE, 10 / pixels), ((member.shell?.height ?? 60) / (member.shell?.storeys ?? 8)) * 0.5);
|
|
140
|
+
for (const slab of member.slabs) {
|
|
141
|
+
const chosen = member.plate?.floor === slab.floor;
|
|
142
|
+
// The great dojo's floor, seen with every floor, has its own slab; and a solid building hides what is in it.
|
|
143
|
+
if (!chosen && ((member.plate === undefined && slab.floor === 7) || options.building === "solid"))
|
|
144
|
+
continue;
|
|
145
|
+
const ids = chosen ? { top: `${prefix}plate`, side: `${prefix}plate-s` } : { top: `${prefix}plate-f${slab.floor}-top`, side: `${prefix}plate-f${slab.floor}-s` };
|
|
146
|
+
const planes = slabPlanes(placed.footprint, slab.level, thick, ids, chosen ? "chosen" : "faint").map((p) => ({ ...p, group: i }));
|
|
147
|
+
items.push({ id: ids.top, kind: "deck", at: placed.at, height: slab.level, planes });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (member.plate !== undefined) {
|
|
151
|
+
const { floor, level } = member.plate;
|
|
152
|
+
const label = KODOKAN_FLOORS.find((f) => f.floor === floor)?.label[language] ?? String(floor);
|
|
153
|
+
const size = Math.max(plan.view.w, plan.view.h) * 0.018;
|
|
154
|
+
items.push({ id: `${prefix}plate-name`, kind: "scoreboard", at: placed.at, height: level + size * 1.7, planes: [sign(`${prefix}plate-name`, label, placed.at, level + size * 0.4, size, i)] });
|
|
87
155
|
}
|
|
88
|
-
if (model.defs !== "")
|
|
89
|
-
defs.push(model.defs);
|
|
90
|
-
if (crowdStyle === "" && model.crowdStyle !== "")
|
|
91
|
-
crowdStyle = model.crowdStyle;
|
|
92
156
|
});
|
|
157
|
+
// The buildings round the venues stand apart from them: each block's planes are of no venue's group.
|
|
158
|
+
if (plan.context !== undefined)
|
|
159
|
+
for (const item of contextUprights(plan.context))
|
|
160
|
+
items.push({ ...item, planes: item.planes.map((p) => ({ ...p, group: APART })) });
|
|
93
161
|
if (labels) {
|
|
94
162
|
const size = Math.max(plan.view.w, plan.view.h) * (plan.mode === "city" ? 0.016 : 0.022);
|
|
95
163
|
plan.members.forEach((placed, i) => {
|
|
@@ -106,7 +174,7 @@ export function buildDistrictTurn(options, settings = {}) {
|
|
|
106
174
|
const planes = planesOf(uprights);
|
|
107
175
|
const box = sceneBox(planes, area, 0, centre, scale);
|
|
108
176
|
// (The floor has no names: the 3D view's own signs, which face the eye, carry them.)
|
|
109
|
-
const floor = drawDistrict({ ...options, id: base, labels: false }, plan, (member, i) => drawMember(member, { ...options, id: base }, i, base, { floor: true }));
|
|
177
|
+
const floor = drawDistrict({ ...options, id: base, labels: false }, plan, (member, i, part) => drawMember(member, { ...options, id: base }, i, base, { floor: true }, part));
|
|
110
178
|
const { title, description } = describeDistrict(options, plan);
|
|
111
179
|
const presets = districtPresets(plan);
|
|
112
180
|
const surfaceLike = { sport: "soccer", language, ...(options.theme === undefined ? {} : { theme: options.theme }), ...(options.style === undefined ? {} : { style: options.style }) };
|
|
@@ -136,6 +204,8 @@ export function buildDistrictTurn(options, settings = {}) {
|
|
|
136
204
|
lens: 12,
|
|
137
205
|
flat: drawDistrict(options, plan),
|
|
138
206
|
groups: plan.members.map((p) => ({ hull: hullOf(p.footprint) })),
|
|
207
|
+
// The crowd outside, when the district asks for one and has a mask to put it on: the mount paints it on a canvas on the floor.
|
|
208
|
+
...(options.outside !== undefined && hasOutside(plan) ? { outside: { level: outsideLevelOf(options), crowd: () => outsideCrowd(plan), viewBox: { x: view.x, y: view.y, w: view.w, h: view.h } } } : {}),
|
|
139
209
|
};
|
|
140
210
|
}
|
|
141
211
|
/**
|
package/dist/gates.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type LonLat } from "./venues.geo.ts";
|
|
2
|
+
/** How a gate is known: `documented` is what a source cited with it says; `plausible` is ours. */
|
|
3
|
+
export type GateBasis = "documented" | "plausible";
|
|
4
|
+
/** What is said of a venue's gate: the way it faces, and what is read from where. */
|
|
5
|
+
export interface GateFact {
|
|
6
|
+
/** A key that is the same on every run: `south`, `south-west-corner`. */
|
|
7
|
+
id: string;
|
|
8
|
+
/** The bearing of the gate's outward normal, degrees clockwise from north, 0 to under 360. */
|
|
9
|
+
bearing: number;
|
|
10
|
+
/** The name where a source gives one (`Gate G`); a plain description of where it is otherwise. */
|
|
11
|
+
name?: {
|
|
12
|
+
en: string;
|
|
13
|
+
ja: string;
|
|
14
|
+
};
|
|
15
|
+
basis: GateBasis;
|
|
16
|
+
read: string;
|
|
17
|
+
}
|
|
18
|
+
/** A gate, placed on a venue's outline. */
|
|
19
|
+
export interface Gate {
|
|
20
|
+
/** `bc-place:south`: the venue's id and the gate's. */
|
|
21
|
+
key: string;
|
|
22
|
+
venue: string;
|
|
23
|
+
id: string;
|
|
24
|
+
name: {
|
|
25
|
+
en: string;
|
|
26
|
+
ja: string;
|
|
27
|
+
};
|
|
28
|
+
/** Where it stands on the outline, `[longitude, latitude]`. */
|
|
29
|
+
at: LonLat;
|
|
30
|
+
/** The bearing of its outward normal, degrees clockwise from north: the way a queue at it runs. */
|
|
31
|
+
bearing: number;
|
|
32
|
+
basis: GateBasis;
|
|
33
|
+
read: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The facts of each venue's gates. BC Place: the English Wikipedia article (revision 1372065649) says a tear in the old roof was "close to Gate G on the south side where the roof meets the top of the concrete bowl", so there is a
|
|
37
|
+
* Gate G on the south side (documented); the other seven are ours, one to each side of the building, on the street sides the brief names (Pacific Boulevard to the south, Robson and Beatty Streets). Rogers Arena: the brief's corner
|
|
38
|
+
* entrance plazas on the Pat Quinn Way side, the south front and the two south corners, and one at the north-west, all ours.
|
|
39
|
+
*/
|
|
40
|
+
export declare const GATE_FACTS: Readonly<Record<string, readonly GateFact[]>>;
|
|
41
|
+
/** The ids of the venues that have gates. */
|
|
42
|
+
export declare const GATE_VENUES: readonly string[];
|
|
43
|
+
/** The name of a gate in a language: the source's where there is one, else its side (`South-west gate`). */
|
|
44
|
+
export declare function gateName(fact: GateFact, language: "en" | "ja"): string;
|
|
45
|
+
/**
|
|
46
|
+
* The gates of a venue (`bc-place`, `rogers-arena`), each on the building's outline where a ray from the middle of the surface at its bearing meets it; empty for a venue with none. A gate whose ray misses the outline is left out
|
|
47
|
+
* (none does for the venues here: a test holds it).
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { venueGates } from "@johnmorrisdotca/kyogijo-stadiums/district";
|
|
51
|
+
* const gates = venueGates("bc-place");
|
|
52
|
+
* console.log(gates.length, gates.filter((g) => g.basis === "documented").map((g) => g.name.en).join(", "));
|
|
53
|
+
* // 8 Gate G
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function venueGates(id: string): Gate[];
|
package/dist/gates.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// The gates of a real venue: where the crowd goes in. A gate is a point on the building's outline (OpenStreetMap's, ODbL 1.0) with the way it faces (the bearing of its outward normal, degrees clockwise from north), a name in English
|
|
2
|
+
// and Japanese, and how it is known: `documented` where a source cited with it says it, `plausible` where it is ours (a gate on each street side, put where a ray from the middle of the surface at the bearing meets the outline).
|
|
3
|
+
// The data is the gates' list of facts (`GATE_FACTS`, with what each cites); the positions are worked out from the outline, so a venue whose outline changes keeps its gates on it. This is the data the crowd's timelapse will use
|
|
4
|
+
// for queues and entrances: where people stand in a line, which way the line runs (away from the gate along its bearing) and where the walkable ground starts. Pure: ids in, gates out.
|
|
5
|
+
import { stadiumById } from "./stadiums.js";
|
|
6
|
+
import { venueById } from "./venues.js";
|
|
7
|
+
import { lonLatFrom, metresFrom } from "./venues.geo.js";
|
|
8
|
+
const WIND = [
|
|
9
|
+
{ en: "north", ja: "北" },
|
|
10
|
+
{ en: "north-east", ja: "北東" },
|
|
11
|
+
{ en: "east", ja: "東" },
|
|
12
|
+
{ en: "south-east", ja: "南東" },
|
|
13
|
+
{ en: "south", ja: "南" },
|
|
14
|
+
{ en: "south-west", ja: "南西" },
|
|
15
|
+
{ en: "west", ja: "西" },
|
|
16
|
+
{ en: "north-west", ja: "北西" },
|
|
17
|
+
];
|
|
18
|
+
const ours = (reason) => `ours: ${reason}`;
|
|
19
|
+
/** A gate on each of the eight sides of a building: ours, the sources say that a stadium has gates and not where each is. */
|
|
20
|
+
const SIDES = (venue) => WIND.map((_, i) => ({ id: WIND[i].en, bearing: i * 45, basis: "plausible", read: ours(`one gate on each of the eight sides of ${venue}'s building: the sources say that it has gates round the bowl and not where each is`) }));
|
|
21
|
+
/**
|
|
22
|
+
* The facts of each venue's gates. BC Place: the English Wikipedia article (revision 1372065649) says a tear in the old roof was "close to Gate G on the south side where the roof meets the top of the concrete bowl", so there is a
|
|
23
|
+
* Gate G on the south side (documented); the other seven are ours, one to each side of the building, on the street sides the brief names (Pacific Boulevard to the south, Robson and Beatty Streets). Rogers Arena: the brief's corner
|
|
24
|
+
* entrance plazas on the Pat Quinn Way side, the south front and the two south corners, and one at the north-west, all ours.
|
|
25
|
+
*/
|
|
26
|
+
export const GATE_FACTS = Object.freeze({
|
|
27
|
+
"bc-place": SIDES("BC Place").map((g) => (g.id === "south" ? { ...g, name: { en: "Gate G", ja: "ゲートG" }, basis: "documented", read: "the English Wikipedia article on BC Place, revision 1372065649: a tear in the old roof 'close to Gate G on the south side'; where on the south side is ours" } : g)),
|
|
28
|
+
"rogers-arena": [
|
|
29
|
+
{ id: "south", bearing: 180, basis: "plausible", read: ours("the main front of the building faces Pat Quinn Way to the south, as the brief says") },
|
|
30
|
+
{ id: "south-west", bearing: 225, basis: "plausible", read: ours("a corner entrance plaza on the Pat Quinn Way side, as the brief says") },
|
|
31
|
+
{ id: "south-east", bearing: 135, basis: "plausible", read: ours("a corner entrance plaza on the Pat Quinn Way side, as the brief says") },
|
|
32
|
+
{ id: "north-west", bearing: 315, basis: "plausible", read: ours("a gate on the side of the Georgia Viaduct and the towers, one of those the brief asks for at the corners") },
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
/** The ids of the venues that have gates. */
|
|
36
|
+
export const GATE_VENUES = Object.freeze(Object.keys(GATE_FACTS));
|
|
37
|
+
/** The point where a ray from the origin at a compass bearing first meets a ring (both in metres east and north of the origin), or `undefined`. */
|
|
38
|
+
function hit(ring, bearing) {
|
|
39
|
+
const a = (bearing * Math.PI) / 180;
|
|
40
|
+
const [dx, dy] = [Math.sin(a), Math.cos(a)];
|
|
41
|
+
let best;
|
|
42
|
+
ring.forEach(([ax, ay], i) => {
|
|
43
|
+
const [bx, by] = ring[(i + 1) % ring.length];
|
|
44
|
+
const [ex, ey] = [bx - ax, by - ay];
|
|
45
|
+
const den = dx * ey - dy * ex;
|
|
46
|
+
if (Math.abs(den) < 1e-12)
|
|
47
|
+
return;
|
|
48
|
+
const t = (ax * ey - ay * ex) / den;
|
|
49
|
+
const u = (ax * dy - ay * dx) / den;
|
|
50
|
+
if (t > 1e-6 && u >= 0 && u <= 1 && (best === undefined || t < best))
|
|
51
|
+
best = t;
|
|
52
|
+
});
|
|
53
|
+
return best === undefined ? undefined : [dx * best, dy * best];
|
|
54
|
+
}
|
|
55
|
+
/** The outline and the middle of a venue's surface that its gates are placed from, `[longitude, latitude]`: an arena's, or a stadium's. */
|
|
56
|
+
function outlineOf(id) {
|
|
57
|
+
const venue = venueById(id);
|
|
58
|
+
if (venue !== undefined)
|
|
59
|
+
return { ring: venue.osm.ring, centre: venue.osm.axis.centre };
|
|
60
|
+
const stadium = stadiumById(id);
|
|
61
|
+
return stadium === undefined ? undefined : { ring: stadium.osm.ring, centre: stadium.osm.axis.centre };
|
|
62
|
+
}
|
|
63
|
+
/** The name of a gate in a language: the source's where there is one, else its side (`South-west gate`). */
|
|
64
|
+
export function gateName(fact, language) {
|
|
65
|
+
if (fact.name !== undefined)
|
|
66
|
+
return fact.name[language];
|
|
67
|
+
const side = WIND.find((w) => w.en === fact.id.replace(/-corner$/, ""));
|
|
68
|
+
return language === "ja" ? `${side?.ja ?? fact.id}ゲート` : `${(side?.en ?? fact.id).replace(/^./, (c) => c.toUpperCase())} gate`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The gates of a venue (`bc-place`, `rogers-arena`), each on the building's outline where a ray from the middle of the surface at its bearing meets it; empty for a venue with none. A gate whose ray misses the outline is left out
|
|
72
|
+
* (none does for the venues here: a test holds it).
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { venueGates } from "@johnmorrisdotca/kyogijo-stadiums/district";
|
|
76
|
+
* const gates = venueGates("bc-place");
|
|
77
|
+
* console.log(gates.length, gates.filter((g) => g.basis === "documented").map((g) => g.name.en).join(", "));
|
|
78
|
+
* // 8 Gate G
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function venueGates(id) {
|
|
82
|
+
const facts = GATE_FACTS[id];
|
|
83
|
+
const outline = outlineOf(id);
|
|
84
|
+
if (facts === undefined || outline === undefined)
|
|
85
|
+
return [];
|
|
86
|
+
const ring = metresFrom(outline.centre, outline.ring);
|
|
87
|
+
const gates = [];
|
|
88
|
+
for (const fact of facts) {
|
|
89
|
+
const p = hit(ring, fact.bearing);
|
|
90
|
+
if (p === undefined)
|
|
91
|
+
continue;
|
|
92
|
+
gates.push({ key: `${id}:${fact.id}`, venue: id, id: fact.id, name: { en: gateName(fact, "en"), ja: gateName(fact, "ja") }, at: lonLatFrom(outline.centre, p).map((x) => Math.round(x * 1e6) / 1e6), bearing: fact.bearing, basis: fact.basis, read: fact.read });
|
|
93
|
+
}
|
|
94
|
+
return gates;
|
|
95
|
+
}
|
package/dist/halls.d.ts
CHANGED
|
@@ -61,5 +61,7 @@ export interface Hall {
|
|
|
61
61
|
ja: string;
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
/** The Kodokan's main dojo as drawn: a square floor of 420 jō's area, four contest areas, the seat of honour, the banner, the wood and the gallery, in the two looks the owner's photographs show. The years of both are unknown. */
|
|
65
|
+
export declare const KODOKAN_MAIN: DojoSpec;
|
|
64
66
|
/** The halls, in the order of their surfaces' fame: the Kodokan, the Budokan, the Kokugikan, the Butokuden and the Budokwai. */
|
|
65
67
|
export declare const HALLS: readonly Hall[];
|
package/dist/halls.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The Kodokan's main dojo as drawn: a square floor of 420 jō's area, four contest areas, the seat of honour, the banner, the wood and the gallery, in the two looks the owner's photographs show. The years of both are unknown. */
|
|
2
|
-
const KODOKAN_MAIN = {
|
|
2
|
+
export const KODOKAN_MAIN = {
|
|
3
3
|
mats: { width: 26.4, length: 26.4 },
|
|
4
4
|
surround: 4,
|
|
5
5
|
areas: { across: 2, down: 2 },
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { DistrictMember } from "./district.ts";
|
|
2
|
+
import type { DojoSpec, Language } from "./types.ts";
|
|
3
|
+
/** The main dojo as the district draws it: the atlas's floor and fittings, with no wood round the mats (the 4 metres the atlas draws would not stand inside the real building). */
|
|
4
|
+
export declare const KODOKAN_DOJO: DojoSpec;
|
|
5
|
+
/** How high the room stands, floor to the top of its lid, in metres: the 3D build's own figure (walls of 4.5 metres, the gallery level with their tops, the lid over it), two storeys of the building. Ours. */
|
|
6
|
+
export declare const KODOKAN_ROOM_HEIGHT = 11.2;
|
|
7
|
+
/** The height of the main dojo's floor above the ground, in metres: the 7th floor, six storeys up at the building's own storey height (its height over its storeys, 5.4 metres), and no higher than leaves the room under the roof. */
|
|
8
|
+
export declare const KODOKAN_FLOOR_HEIGHT: number;
|
|
9
|
+
/** Where the Kodokan's building stands and what it is: for tests and pages that say it. */
|
|
10
|
+
export declare const KODOKAN: {
|
|
11
|
+
readonly floorHeight: number;
|
|
12
|
+
readonly roomHeight: 11.2;
|
|
13
|
+
readonly mats: 420;
|
|
14
|
+
readonly seats: 900;
|
|
15
|
+
readonly source: "bldg_ec4aa7a9-f8cb-4abb-af0c-a2cef6d06dd8";
|
|
16
|
+
readonly read: "2026-10-22";
|
|
17
|
+
readonly ring: readonly [readonly [139.753281, 35.707485], readonly [139.753287, 35.707464], readonly [139.753659, 35.707456], readonly [139.753548, 35.707846], readonly [139.753502, 35.707837], readonly [139.753496, 35.707859], readonly [139.753195, 35.707801], readonly [139.753268, 35.707546], readonly [139.753193, 35.707532], readonly [139.75321, 35.707472]];
|
|
18
|
+
readonly height: 43.1;
|
|
19
|
+
readonly storeys: 8;
|
|
20
|
+
readonly room: {
|
|
21
|
+
readonly centre: readonly [139.75342, 35.707654];
|
|
22
|
+
readonly heading: 77;
|
|
23
|
+
readonly side: 31.8;
|
|
24
|
+
readonly clearance: 0.18;
|
|
25
|
+
};
|
|
26
|
+
readonly floors: {
|
|
27
|
+
readonly "5": {
|
|
28
|
+
readonly heading: 167;
|
|
29
|
+
readonly clearance: 2.59;
|
|
30
|
+
readonly rooms: readonly [{
|
|
31
|
+
readonly id: "womens";
|
|
32
|
+
readonly jo: 240;
|
|
33
|
+
readonly w: 27.3;
|
|
34
|
+
readonly l: 14.56;
|
|
35
|
+
readonly centre: readonly [139.753353, 35.707641];
|
|
36
|
+
}, {
|
|
37
|
+
readonly id: "boys";
|
|
38
|
+
readonly jo: 114;
|
|
39
|
+
readonly w: 17.29;
|
|
40
|
+
readonly l: 10.92;
|
|
41
|
+
readonly centre: readonly [139.75352, 35.707624];
|
|
42
|
+
}, {
|
|
43
|
+
readonly id: "special";
|
|
44
|
+
readonly jo: 40;
|
|
45
|
+
readonly w: 9.1;
|
|
46
|
+
readonly l: 7.28;
|
|
47
|
+
readonly centre: readonly [139.753483, 35.707752];
|
|
48
|
+
}];
|
|
49
|
+
};
|
|
50
|
+
readonly "6": {
|
|
51
|
+
readonly heading: 77;
|
|
52
|
+
readonly clearance: 2.43;
|
|
53
|
+
readonly rooms: readonly [{
|
|
54
|
+
readonly id: "school";
|
|
55
|
+
readonly jo: 240;
|
|
56
|
+
readonly w: 27.3;
|
|
57
|
+
readonly l: 14.56;
|
|
58
|
+
readonly centre: readonly [139.7534, 35.707724];
|
|
59
|
+
}, {
|
|
60
|
+
readonly id: "international";
|
|
61
|
+
readonly jo: 192;
|
|
62
|
+
readonly w: 21.84;
|
|
63
|
+
readonly l: 14.56;
|
|
64
|
+
readonly centre: readonly [139.75344, 35.707583];
|
|
65
|
+
}];
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/** A room of a floor of the Kodokan: what the Kodokan's floor guide calls it, its count of jō where the guide gives one, and whether the room is drawn from that count or is ours. */
|
|
70
|
+
export interface KodokanRoom {
|
|
71
|
+
id: string;
|
|
72
|
+
name: {
|
|
73
|
+
en: string;
|
|
74
|
+
ja: string;
|
|
75
|
+
};
|
|
76
|
+
/** Mats, in jō: the guide's count; `null` where it gives none (the special dojo: drawn at 40 jō, ours). */
|
|
77
|
+
mats: number | null;
|
|
78
|
+
/** The count the room is drawn at: the guide's, or ours where it gives none. */
|
|
79
|
+
drawn: number;
|
|
80
|
+
}
|
|
81
|
+
/** A floor of the Kodokan International Judo Center, the new building: its label, what the Kodokan's own floor guide lists on it, what is drawn there, and where the words come from. */
|
|
82
|
+
export interface KodokanFloor {
|
|
83
|
+
/** 0 is the basement, 1 to 8 the floors above the ground. */
|
|
84
|
+
floor: number;
|
|
85
|
+
label: {
|
|
86
|
+
en: string;
|
|
87
|
+
ja: string;
|
|
88
|
+
};
|
|
89
|
+
/** What the floor guide lists on it, in each language (a floor with no entry of its own says what a second source says, `else`). */
|
|
90
|
+
lists: {
|
|
91
|
+
en: string;
|
|
92
|
+
ja: string;
|
|
93
|
+
};
|
|
94
|
+
rooms: KodokanRoom[];
|
|
95
|
+
/** What the view draws: the `rooms` the guide counts, the `great-dojo`, its `gallery`, only the floor's `plate` (nothing is published of its rooms), or `none` (under the ground). */
|
|
96
|
+
drawn: "rooms" | "great-dojo" | "gallery" | "plate" | "none";
|
|
97
|
+
/** Where the floor's words come from: the Kodokan's floor guide, and English Wikipedia where the guide says nothing. */
|
|
98
|
+
source: "kodokan" | "wikipedia";
|
|
99
|
+
}
|
|
100
|
+
/** The floors, from the basement up. The Kodokan's floor guide (施設のご案内, `docs/district.md`) lists 8F to B1; its 1F entry is empty, so the 1st floor is English Wikipedia's. */
|
|
101
|
+
export declare const KODOKAN_FLOORS: readonly KodokanFloor[];
|
|
102
|
+
/** The floors a district can be asked for: 0 (the basement) to 8. */
|
|
103
|
+
export declare const KODOKAN_FLOOR_IDS: readonly number[];
|
|
104
|
+
/** The height of a floor's level above the ground, in metres: the building's height over its storeys, for each floor under it (ours: the storeys are not all one height). */
|
|
105
|
+
export declare const kodokanLevel: (floor: number) => number;
|
|
106
|
+
/** How thick a floor of the building is drawn, in metres: its slab and its beams. Ours: a reinforced-concrete floor with its beams is some 0.4 to 0.8 metres of structure; the figure is a plausible one, and a floor is drawn no thinner than 10 pixels at the page's own size (`kodokanSlab`). */
|
|
107
|
+
export declare const KODOKAN_SLAB = 0.6;
|
|
108
|
+
/** The level of a floor's slab, in metres: the building's own storeys, except that the 7th is the great dojo's floor and the 8th the gallery's level over it. */
|
|
109
|
+
export declare const kodokanSlabLevel: (floor: number) => number;
|
|
110
|
+
/** The height of the gallery's level over the main dojo's floor, in feet: the room's walls, 4.5 metres. A plane that begins above it is the 8th floor's. */
|
|
111
|
+
export declare const KODOKAN_GALLERY_LEVEL: number;
|
|
112
|
+
/**
|
|
113
|
+
* The Kodokan as a member of a district. With a `floor`, it is that floor of the building: the 7th is the great dojo, the 8th its gallery, the 5th and 6th their dojos as the floor guide counts them (laid out by us), the others plain floor plates;
|
|
114
|
+
* the basement is under the ground and draws nothing. Throws for a floor that is not 0 to 8.
|
|
115
|
+
*/
|
|
116
|
+
export declare function kodokanMember(language: Language, floor?: number): DistrictMember;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** The Kodokan's building and the place of its main dojo in it. */
|
|
2
|
+
export declare const KODOKAN_BUILDING: {
|
|
3
|
+
/** The building's id in PLATEAU's file (bldg:Building gml:id). */
|
|
4
|
+
readonly source: "bldg_ec4aa7a9-f8cb-4abb-af0c-a2cef6d06dd8";
|
|
5
|
+
readonly read: "2026-10-22";
|
|
6
|
+
/** The roof-edge outline, `[longitude, latitude]`. */
|
|
7
|
+
readonly ring: readonly [readonly [139.753281, 35.707485], readonly [139.753287, 35.707464], readonly [139.753659, 35.707456], readonly [139.753548, 35.707846], readonly [139.753502, 35.707837], readonly [139.753496, 35.707859], readonly [139.753195, 35.707801], readonly [139.753268, 35.707546], readonly [139.753193, 35.707532], readonly [139.75321, 35.707472]];
|
|
8
|
+
/** The height of the building's top above its ground, in metres, and its storeys above ground. */
|
|
9
|
+
readonly height: 43.1;
|
|
10
|
+
readonly storeys: 8;
|
|
11
|
+
/** The middle of the main dojo's room, `[longitude, latitude]`, the compass heading of its x axis (0 to under 180) and the length of its side in metres, walls and gallery included. */
|
|
12
|
+
readonly room: {
|
|
13
|
+
readonly centre: readonly [139.75342, 35.707654];
|
|
14
|
+
readonly heading: 77;
|
|
15
|
+
readonly side: 31.8;
|
|
16
|
+
readonly clearance: 0.18;
|
|
17
|
+
};
|
|
18
|
+
/** The rooms of the 5th and 6th floors: each floor's heading (of its rooms' x axis), and for each room its count in jo, its size in metres (the dojo builder's shape for the count) and the middle of it, `[longitude, latitude]`. Ours but the counts. */
|
|
19
|
+
readonly floors: {
|
|
20
|
+
readonly "5": {
|
|
21
|
+
readonly heading: 167;
|
|
22
|
+
readonly clearance: 2.59;
|
|
23
|
+
readonly rooms: readonly [{
|
|
24
|
+
readonly id: "womens";
|
|
25
|
+
readonly jo: 240;
|
|
26
|
+
readonly w: 27.3;
|
|
27
|
+
readonly l: 14.56;
|
|
28
|
+
readonly centre: readonly [139.753353, 35.707641];
|
|
29
|
+
}, {
|
|
30
|
+
readonly id: "boys";
|
|
31
|
+
readonly jo: 114;
|
|
32
|
+
readonly w: 17.29;
|
|
33
|
+
readonly l: 10.92;
|
|
34
|
+
readonly centre: readonly [139.75352, 35.707624];
|
|
35
|
+
}, {
|
|
36
|
+
readonly id: "special";
|
|
37
|
+
readonly jo: 40;
|
|
38
|
+
readonly w: 9.1;
|
|
39
|
+
readonly l: 7.28;
|
|
40
|
+
readonly centre: readonly [139.753483, 35.707752];
|
|
41
|
+
}];
|
|
42
|
+
};
|
|
43
|
+
readonly "6": {
|
|
44
|
+
readonly heading: 77;
|
|
45
|
+
readonly clearance: 2.43;
|
|
46
|
+
readonly rooms: readonly [{
|
|
47
|
+
readonly id: "school";
|
|
48
|
+
readonly jo: 240;
|
|
49
|
+
readonly w: 27.3;
|
|
50
|
+
readonly l: 14.56;
|
|
51
|
+
readonly centre: readonly [139.7534, 35.707724];
|
|
52
|
+
}, {
|
|
53
|
+
readonly id: "international";
|
|
54
|
+
readonly jo: 192;
|
|
55
|
+
readonly w: 21.84;
|
|
56
|
+
readonly l: 14.56;
|
|
57
|
+
readonly centre: readonly [139.75344, 35.707583];
|
|
58
|
+
}];
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Made by scripts/build-plateau.mjs from data-sources/plateau/2026-10-22/: do not edit by hand.
|
|
2
|
+
//
|
|
3
|
+
// THIS FILE IS DATA FROM PROJECT PLATEAU, edited: the Kodokan's building (its roof-edge outline simplified to 0.3 metres, its height and its storeys, from MLIT's 3D city model of Bunkyo ward, 2025 edition) and where the main dojo's
|
|
4
|
+
// room is put in it (worked out here from the outline, ours). The credit is `PLATEAU_ATTRIBUTION` (plateau.credit.ts), the terms the PLATEAU Site Policy's (free, commercial use included, compatible with CC BY 4.0). Apart from the
|
|
5
|
+
// OpenStreetMap data (ODbL 1.0); nothing is copied from one to the other. The raw extract is in data-sources/plateau/.
|
|
6
|
+
/** The Kodokan's building and the place of its main dojo in it. */
|
|
7
|
+
export const KODOKAN_BUILDING = {
|
|
8
|
+
/** The building's id in PLATEAU's file (bldg:Building gml:id). */
|
|
9
|
+
"source": "bldg_ec4aa7a9-f8cb-4abb-af0c-a2cef6d06dd8",
|
|
10
|
+
"read": "2026-10-22",
|
|
11
|
+
/** The roof-edge outline, `[longitude, latitude]`. */
|
|
12
|
+
"ring": [[139.753281, 35.707485], [139.753287, 35.707464], [139.753659, 35.707456], [139.753548, 35.707846], [139.753502, 35.707837], [139.753496, 35.707859], [139.753195, 35.707801], [139.753268, 35.707546], [139.753193, 35.707532], [139.75321, 35.707472]],
|
|
13
|
+
/** The height of the building's top above its ground, in metres, and its storeys above ground. */
|
|
14
|
+
"height": 43.1,
|
|
15
|
+
"storeys": 8,
|
|
16
|
+
/** The middle of the main dojo's room, `[longitude, latitude]`, the compass heading of its x axis (0 to under 180) and the length of its side in metres, walls and gallery included. */
|
|
17
|
+
"room": { "centre": [139.75342, 35.707654], "heading": 77, "side": 31.8, "clearance": 0.18 },
|
|
18
|
+
/** The rooms of the 5th and 6th floors: each floor's heading (of its rooms' x axis), and for each room its count in jo, its size in metres (the dojo builder's shape for the count) and the middle of it, `[longitude, latitude]`. Ours but the counts. */
|
|
19
|
+
"floors": { "5": { "heading": 167, "clearance": 2.59, "rooms": [{ "id": "womens", "jo": 240, "w": 27.3, "l": 14.56, "centre": [139.753353, 35.707641] }, { "id": "boys", "jo": 114, "w": 17.29, "l": 10.92, "centre": [139.75352, 35.707624] }, { "id": "special", "jo": 40, "w": 9.1, "l": 7.28, "centre": [139.753483, 35.707752] }] }, "6": { "heading": 77, "clearance": 2.43, "rooms": [{ "id": "school", "jo": 240, "w": 27.3, "l": 14.56, "centre": [139.7534, 35.707724] }, { "id": "international", "jo": 192, "w": 21.84, "l": 14.56, "centre": [139.75344, 35.707583] }] } },
|
|
20
|
+
};
|
package/dist/kodokan.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// The Kodokan (講道館) as a venue of a district: its building, from Project PLATEAU, and its main dojo (大道場), the room on the 7th floor with its gallery on the 8th, drawn in the air on its real floor over the building's own outline.
|
|
2
|
+
// The facts that are documented are the count (420 jō of mats, four contest areas at once), the floor (the 7th), the gallery (the 8th, about 900) and the building (8 floors and a basement; PLATEAU: 8 storeys above ground, 43.1 metres): the Kodokan's own page, English
|
|
3
|
+
// Wikipedia and the IJF say the first four (`docs/district.md`, "The Kodokan"). Ours: the shape of the floor (no source gives it: a square of 26.4 metres, the area of 420 jō, on which four areas of 8 metres fit, as `halls.ts` draws it), the room's place in the
|
|
4
|
+
// building (the square that stands farthest from its walls, `scripts/build-plateau.mjs`), the wood round the mats (none, so that the room fits the real outline) and the height of the 7th floor (six storeys of the building's own). Pure data and a few sums.
|
|
5
|
+
import { FEET_PER_METRE } from "./geometry.js";
|
|
6
|
+
import { KODOKAN_MAIN } from "./halls.js";
|
|
7
|
+
import { KODOKAN_BUILDING as BUILDING } from "./kodokan.data.js";
|
|
8
|
+
import { PLATEAU_ATTRIBUTION } from "./plateau.credit.js";
|
|
9
|
+
/** The main dojo as the district draws it: the atlas's floor and fittings, with no wood round the mats (the 4 metres the atlas draws would not stand inside the real building). */
|
|
10
|
+
export const KODOKAN_DOJO = { ...KODOKAN_MAIN, surround: 0 };
|
|
11
|
+
/** How high the room stands, floor to the top of its lid, in metres: the 3D build's own figure (walls of 4.5 metres, the gallery level with their tops, the lid over it), two storeys of the building. Ours. */
|
|
12
|
+
export const KODOKAN_ROOM_HEIGHT = 11.2;
|
|
13
|
+
/** The height of the main dojo's floor above the ground, in metres: the 7th floor, six storeys up at the building's own storey height (its height over its storeys, 5.4 metres), and no higher than leaves the room under the roof. */
|
|
14
|
+
export const KODOKAN_FLOOR_HEIGHT = Math.min((6 * BUILDING.height) / BUILDING.storeys, BUILDING.height - KODOKAN_ROOM_HEIGHT);
|
|
15
|
+
/** Where the Kodokan's building stands and what it is: for tests and pages that say it. */
|
|
16
|
+
export const KODOKAN = { ...BUILDING, floorHeight: KODOKAN_FLOOR_HEIGHT, roomHeight: KODOKAN_ROOM_HEIGHT, mats: 420, seats: 900 };
|
|
17
|
+
/** The floors, from the basement up. The Kodokan's floor guide (施設のご案内, `docs/district.md`) lists 8F to B1; its 1F entry is empty, so the 1st floor is English Wikipedia's. */
|
|
18
|
+
export const KODOKAN_FLOORS = [
|
|
19
|
+
{ floor: 0, label: { en: "B1", ja: "地下1階" }, lists: { en: "dining hall, training room, disaster-prevention centre", ja: "食堂、トレーニングルーム、防災センター" }, rooms: [], drawn: "none", source: "kodokan" },
|
|
20
|
+
{ floor: 1, label: { en: "1F", ja: "1階" }, lists: { en: "parking, a bank and a store (the floor guide lists nothing here)", ja: "駐車場、銀行、売店(いずれも公式の案内には記載なし)" }, rooms: [], drawn: "plate", source: "wikipedia" },
|
|
21
|
+
{ floor: 2, label: { en: "2F", ja: "2階" }, lists: { en: "museum and library, classroom, meeting rooms 3 and 4", ja: "資料館・図書館、教室、第3会議室、第4会議室" }, rooms: [], drawn: "plate", source: "kodokan" },
|
|
22
|
+
{ floor: 3, label: { en: "3F", ja: "3階" }, lists: { en: "accommodation", ja: "宿泊施設" }, rooms: [], drawn: "plate", source: "kodokan" },
|
|
23
|
+
{ floor: 4, label: { en: "4F", ja: "4階" }, lists: { en: "dojo guidance office, dojo reception, changing rooms", ja: "道場指導部、道場受付、更衣室(ロッカールーム)" }, rooms: [], drawn: "plate", source: "kodokan" },
|
|
24
|
+
{
|
|
25
|
+
floor: 5,
|
|
26
|
+
label: { en: "5F", ja: "5階" },
|
|
27
|
+
lists: { en: "women's dojo (240 jō), boys' dojo (114 jō), special dojo (no count given)", ja: "女子部道場(240畳)、少年部道場(114畳)、特別道場(畳数の記載なし)" },
|
|
28
|
+
rooms: [
|
|
29
|
+
{ id: "womens", name: { en: "Women's dojo", ja: "女子部道場" }, mats: 240, drawn: 240 },
|
|
30
|
+
{ id: "boys", name: { en: "Boys' dojo", ja: "少年部道場" }, mats: 114, drawn: 114 },
|
|
31
|
+
{ id: "special", name: { en: "Special dojo", ja: "特別道場" }, mats: null, drawn: 40 },
|
|
32
|
+
],
|
|
33
|
+
drawn: "rooms",
|
|
34
|
+
source: "kodokan",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
floor: 6,
|
|
38
|
+
label: { en: "6F", ja: "6階" },
|
|
39
|
+
lists: { en: "school dojo (240 jō), international dojo (192 jō)", ja: "学校道場(240畳)、国際部道場(192畳)" },
|
|
40
|
+
rooms: [
|
|
41
|
+
{ id: "school", name: { en: "School dojo", ja: "学校道場" }, mats: 240, drawn: 240 },
|
|
42
|
+
{ id: "international", name: { en: "International dojo", ja: "国際部道場" }, mats: 192, drawn: 192 },
|
|
43
|
+
],
|
|
44
|
+
drawn: "rooms",
|
|
45
|
+
source: "kodokan",
|
|
46
|
+
},
|
|
47
|
+
{ floor: 7, label: { en: "7F", ja: "7階" }, lists: { en: "main dojo (420 jō)", ja: "大道場(420畳)" }, rooms: [{ id: "main", name: { en: "Main dojo", ja: "大道場" }, mats: 420, drawn: 420 }], drawn: "great-dojo", source: "kodokan" },
|
|
48
|
+
{ floor: 8, label: { en: "8F", ja: "8階" }, lists: { en: "spectators' gallery (about 900 seats)", ja: "見学席(約900席)" }, rooms: [], drawn: "gallery", source: "kodokan" },
|
|
49
|
+
];
|
|
50
|
+
/** The floors a district can be asked for: 0 (the basement) to 8. */
|
|
51
|
+
export const KODOKAN_FLOOR_IDS = KODOKAN_FLOORS.map((f) => f.floor);
|
|
52
|
+
/** The height of a floor's level above the ground, in metres: the building's height over its storeys, for each floor under it (ours: the storeys are not all one height). */
|
|
53
|
+
export const kodokanLevel = (floor) => ((floor - 1) * BUILDING.height) / BUILDING.storeys;
|
|
54
|
+
/** How thick a floor of the building is drawn, in metres: its slab and its beams. Ours: a reinforced-concrete floor with its beams is some 0.4 to 0.8 metres of structure; the figure is a plausible one, and a floor is drawn no thinner than 10 pixels at the page's own size (`kodokanSlab`). */
|
|
55
|
+
export const KODOKAN_SLAB = 0.6;
|
|
56
|
+
/** The level of a floor's slab, in metres: the building's own storeys, except that the 7th is the great dojo's floor and the 8th the gallery's level over it. */
|
|
57
|
+
export const kodokanSlabLevel = (floor) => (floor === 7 ? KODOKAN_FLOOR_HEIGHT : floor === 8 ? KODOKAN_FLOOR_HEIGHT + KODOKAN_GALLERY_LEVEL / FEET_PER_METRE : kodokanLevel(floor));
|
|
58
|
+
/** The height of the gallery's level over the main dojo's floor, in feet: the room's walls, 4.5 metres. A plane that begins above it is the 8th floor's. */
|
|
59
|
+
export const KODOKAN_GALLERY_LEVEL = 4.4 * FEET_PER_METRE;
|
|
60
|
+
const roomOptions = (jo, language) => ({ sport: "dojo", dojo: { mats: jo, surround: 0, kamiza: "north" }, crowd: false, language });
|
|
61
|
+
/**
|
|
62
|
+
* The Kodokan as a member of a district. With a `floor`, it is that floor of the building: the 7th is the great dojo, the 8th its gallery, the 5th and 6th their dojos as the floor guide counts them (laid out by us), the others plain floor plates;
|
|
63
|
+
* the basement is under the ground and draws nothing. Throws for a floor that is not 0 to 8.
|
|
64
|
+
*/
|
|
65
|
+
export function kodokanMember(language, floor) {
|
|
66
|
+
const base = {
|
|
67
|
+
key: "kodokan",
|
|
68
|
+
id: "kodokan",
|
|
69
|
+
kind: "hall",
|
|
70
|
+
name: { en: "Kodokan", ja: "講道館" },
|
|
71
|
+
ring: BUILDING.ring,
|
|
72
|
+
centre: BUILDING.room.centre,
|
|
73
|
+
heading: BUILDING.room.heading,
|
|
74
|
+
basis: "building",
|
|
75
|
+
seats: KODOKAN.seats,
|
|
76
|
+
options: { sport: "dojo", dojo: KODOKAN_DOJO, crowd: { real: true }, language },
|
|
77
|
+
elevation: KODOKAN_FLOOR_HEIGHT * FEET_PER_METRE,
|
|
78
|
+
shell: { height: BUILDING.height * FEET_PER_METRE, storeys: BUILDING.storeys },
|
|
79
|
+
attribution: PLATEAU_ATTRIBUTION,
|
|
80
|
+
slabs: KODOKAN_FLOORS.filter((f) => f.floor >= 1).map((f) => ({ floor: f.floor, level: kodokanSlabLevel(f.floor) * FEET_PER_METRE })),
|
|
81
|
+
slabThickness: KODOKAN_SLAB,
|
|
82
|
+
};
|
|
83
|
+
if (floor === undefined)
|
|
84
|
+
return base;
|
|
85
|
+
if (!Number.isInteger(floor) || !KODOKAN_FLOOR_IDS.includes(floor))
|
|
86
|
+
throw new Error(`the Kodokan has floors ${KODOKAN_FLOOR_IDS.join(", ")} (0 is the basement), not ${String(floor)}`);
|
|
87
|
+
const main = (show) => ({ key: "main", options: base.options, centre: base.centre, heading: base.heading, elevation: base.elevation, show });
|
|
88
|
+
const rooms = BUILDING.floors[String(floor)];
|
|
89
|
+
const parts = floor === 7 ? [main("room")] : floor === 8 ? [main("gallery")] : rooms === undefined ? [] : rooms.rooms.map((r) => ({ key: r.id, options: roomOptions(r.jo, language), centre: r.centre, heading: rooms.heading, elevation: kodokanLevel(floor) * FEET_PER_METRE }));
|
|
90
|
+
// The great dojo's own floor is the 7th's (a little under its storey height, so that the room stays under the roof), and the gallery's level is the room's wall height over it.
|
|
91
|
+
return { ...base, parts, ...(floor >= 1 ? { plate: { floor, level: kodokanSlabLevel(floor) * FEET_PER_METRE } } : {}) };
|
|
92
|
+
}
|