@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.
Files changed (361) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/NOTICE.md +182 -2
  3. package/README.md +106 -19
  4. package/dist/annotate.js +1 -1
  5. package/dist/arenas-entry.d.ts +4 -0
  6. package/dist/arenas-entry.js +3 -0
  7. package/dist/arenas.d.ts +125 -0
  8. package/dist/arenas.data.d.ts +2 -0
  9. package/dist/arenas.data.js +3763 -0
  10. package/dist/arenas.js +72 -0
  11. package/dist/athletics/describe.d.ts +8 -0
  12. package/dist/athletics/describe.js +41 -0
  13. package/dist/athletics/events.d.ts +17 -0
  14. package/dist/athletics/events.js +48 -0
  15. package/dist/athletics/facilities.d.ts +80 -0
  16. package/dist/athletics/facilities.js +176 -0
  17. package/dist/athletics/infield.d.ts +79 -0
  18. package/dist/athletics/infield.js +166 -0
  19. package/dist/athletics/layout.d.ts +13 -0
  20. package/dist/athletics/layout.js +98 -0
  21. package/dist/athletics/oval.d.ts +57 -0
  22. package/dist/athletics/oval.js +116 -0
  23. package/dist/athletics/plan.d.ts +97 -0
  24. package/dist/athletics/plan.js +355 -0
  25. package/dist/athletics/races.d.ts +102 -0
  26. package/dist/athletics/races.js +355 -0
  27. package/dist/athletics/steeplechase.d.ts +72 -0
  28. package/dist/athletics/steeplechase.js +196 -0
  29. package/dist/athletics/stencil.d.ts +13 -0
  30. package/dist/athletics/stencil.js +85 -0
  31. package/dist/athletics/track.d.ts +54 -0
  32. package/dist/athletics/track.js +105 -0
  33. package/dist/athletics/types.d.ts +77 -0
  34. package/dist/athletics/types.js +1 -0
  35. package/dist/athletics-entry.d.ts +17 -0
  36. package/dist/athletics-entry.js +11 -0
  37. package/dist/athletics.style.d.ts +16 -0
  38. package/dist/athletics.style.js +51 -0
  39. package/dist/atlas-entry.d.ts +6 -2
  40. package/dist/atlas-entry.js +4 -2
  41. package/dist/atlas.d.ts +117 -23
  42. package/dist/atlas.js +197 -12
  43. package/dist/background.js +2 -1
  44. package/dist/budo/describe.d.ts +13 -0
  45. package/dist/budo/describe.js +120 -0
  46. package/dist/budo/dojo.api.d.ts +64 -0
  47. package/dist/budo/dojo.api.js +46 -0
  48. package/dist/budo/dojo.d.ts +72 -0
  49. package/dist/budo/dojo.js +300 -0
  50. package/dist/budo/judo.d.ts +61 -0
  51. package/dist/budo/judo.js +109 -0
  52. package/dist/budo/karate.d.ts +29 -0
  53. package/dist/budo/karate.js +80 -0
  54. package/dist/budo/kendo.d.ts +18 -0
  55. package/dist/budo/kendo.js +44 -0
  56. package/dist/budo/kimarite.d.ts +19 -0
  57. package/dist/budo/kimarite.js +33 -0
  58. package/dist/budo/kit.d.ts +16 -0
  59. package/dist/budo/kit.js +24 -0
  60. package/dist/budo/kyudo.d.ts +28 -0
  61. package/dist/budo/kyudo.js +66 -0
  62. package/dist/budo/looks.d.ts +28 -0
  63. package/dist/budo/looks.js +58 -0
  64. package/dist/budo/parts.d.ts +32 -0
  65. package/dist/budo/parts.js +10 -0
  66. package/dist/budo/plan.d.ts +64 -0
  67. package/dist/budo/plan.js +139 -0
  68. package/dist/budo/room.d.ts +133 -0
  69. package/dist/budo/room.js +111 -0
  70. package/dist/budo/sumo.d.ts +31 -0
  71. package/dist/budo/sumo.js +71 -0
  72. package/dist/budo/tatami.d.ts +55 -0
  73. package/dist/budo/tatami.js +156 -0
  74. package/dist/budo/types.d.ts +192 -0
  75. package/dist/budo/types.js +2 -0
  76. package/dist/budo-entry.d.ts +22 -0
  77. package/dist/budo-entry.js +13 -0
  78. package/dist/budo.board.d.ts +28 -0
  79. package/dist/budo.board.js +81 -0
  80. package/dist/budo.score.d.ts +18 -0
  81. package/dist/budo.score.js +52 -0
  82. package/dist/budo.style.d.ts +6 -0
  83. package/dist/budo.style.js +67 -0
  84. package/dist/charts-entry.d.ts +6 -1
  85. package/dist/charts-entry.js +3 -0
  86. package/dist/charts.athletics.d.ts +183 -0
  87. package/dist/charts.athletics.js +455 -0
  88. package/dist/charts.baseball.js +1 -1
  89. package/dist/charts.curling.heat.d.ts +24 -0
  90. package/dist/charts.curling.heat.js +116 -0
  91. package/dist/charts.curling.js +14 -3
  92. package/dist/charts.js +4 -4
  93. package/dist/charts.pool.d.ts +67 -0
  94. package/dist/charts.pool.js +76 -0
  95. package/dist/charts.skating.d.ts +204 -0
  96. package/dist/charts.skating.js +426 -0
  97. package/dist/charts.soccer.js +3 -3
  98. package/dist/charts.types.d.ts +63 -1
  99. package/dist/colour.d.ts +4 -4
  100. package/dist/colour.js +4 -4
  101. package/dist/court.d.ts +85 -2
  102. package/dist/court.js +102 -7
  103. package/dist/court.more.d.ts +46 -0
  104. package/dist/court.more.js +219 -0
  105. package/dist/courts.style.d.ts +14 -2
  106. package/dist/courts.style.js +51 -4
  107. package/dist/crowd.d.ts +164 -0
  108. package/dist/crowd.draw.d.ts +17 -0
  109. package/dist/crowd.draw.js +204 -0
  110. package/dist/crowd.js +480 -0
  111. package/dist/crowd.park.d.ts +19 -0
  112. package/dist/crowd.park.js +153 -0
  113. package/dist/curling.stats.d.ts +271 -0
  114. package/dist/curling.stats.js +301 -0
  115. package/dist/draw.d.ts +16 -0
  116. package/dist/draw.js +462 -54
  117. package/dist/element-entry.d.ts +3 -1
  118. package/dist/element-entry.js +2 -1
  119. package/dist/element.d.ts +13 -2
  120. package/dist/element.js +79 -4
  121. package/dist/emblems-source.d.ts +50 -0
  122. package/dist/emblems-source.js +56 -0
  123. package/dist/eras.d.ts +3 -1
  124. package/dist/eras.js +8 -3
  125. package/dist/features.js +204 -0
  126. package/dist/field.data.d.ts +16 -0
  127. package/dist/field.data.js +50 -0
  128. package/dist/fields.kit.d.ts +2 -2
  129. package/dist/fields.types.d.ts +24 -4
  130. package/dist/formations.js +18 -7
  131. package/dist/formations.sports.d.ts +8 -0
  132. package/dist/formations.sports.js +251 -0
  133. package/dist/frames.providers.js +71 -8
  134. package/dist/geojson.js +3 -0
  135. package/dist/geometry-entry.d.ts +2 -1
  136. package/dist/geometry-entry.js +2 -1
  137. package/dist/geometry.d.ts +20 -0
  138. package/dist/geometry.js +78 -1
  139. package/dist/grounds.d.ts +4 -0
  140. package/dist/grounds.data.js +12 -0
  141. package/dist/halls.d.ts +65 -0
  142. package/dist/halls.js +122 -0
  143. package/dist/hardwood.d.ts +31 -0
  144. package/dist/hardwood.js +157 -0
  145. package/dist/heat.js +21 -13
  146. package/dist/heat.types.d.ts +5 -0
  147. package/dist/heat.zones.d.ts +4 -2
  148. package/dist/heat.zones.js +207 -7
  149. package/dist/homeside.js +24 -0
  150. package/dist/index.d.ts +30 -4
  151. package/dist/index.js +18 -2
  152. package/dist/layers-entry.d.ts +2 -1
  153. package/dist/layers-entry.js +1 -0
  154. package/dist/layers.d.ts +2 -1
  155. package/dist/layers.env.d.ts +12 -1
  156. package/dist/layers.env.js +36 -4
  157. package/dist/layers.js +32 -13
  158. package/dist/layers.types.d.ts +9 -2
  159. package/dist/leagues/athletics.d.ts +63 -0
  160. package/dist/leagues/athletics.js +87 -0
  161. package/dist/leagues/budo.d.ts +196 -0
  162. package/dist/leagues/budo.js +105 -0
  163. package/dist/leagues/courts.d.ts +269 -4
  164. package/dist/leagues/courts.js +155 -1
  165. package/dist/leagues/hockey.js +41 -19
  166. package/dist/leagues/skating.d.ts +145 -0
  167. package/dist/leagues/skating.js +73 -0
  168. package/dist/leagues/sources.js +41 -0
  169. package/dist/leagues/types.d.ts +1 -1
  170. package/dist/leagues-entry.d.ts +4 -2
  171. package/dist/leagues-entry.js +2 -1
  172. package/dist/leagues.d.ts +17 -4
  173. package/dist/leagues.js +246 -5
  174. package/dist/lineup.codes.d.ts +23 -0
  175. package/dist/lineup.codes.js +122 -0
  176. package/dist/logo.d.ts +25 -0
  177. package/dist/logo.js +47 -0
  178. package/dist/look.d.ts +3 -3
  179. package/dist/look.js +39 -6
  180. package/dist/outline.d.ts +1 -1
  181. package/dist/outline.js +46 -4
  182. package/dist/pageant.d.ts +120 -0
  183. package/dist/pageant.draw.d.ts +21 -0
  184. package/dist/pageant.draw.js +171 -0
  185. package/dist/pageant.js +211 -0
  186. package/dist/pageant.style.d.ts +8 -0
  187. package/dist/pageant.style.js +42 -0
  188. package/dist/png.d.ts +8 -1
  189. package/dist/png.js +21 -1
  190. package/dist/pointer-entry.d.ts +2 -0
  191. package/dist/pointer-entry.js +2 -0
  192. package/dist/pointer.d.ts +113 -0
  193. package/dist/pointer.js +151 -0
  194. package/dist/pool.d.ts +176 -0
  195. package/dist/pool.figures.d.ts +306 -0
  196. package/dist/pool.figures.js +148 -0
  197. package/dist/pool.js +304 -0
  198. package/dist/pool.kit.d.ts +48 -0
  199. package/dist/pool.kit.js +141 -0
  200. package/dist/pool.labels.d.ts +20 -0
  201. package/dist/pool.labels.js +258 -0
  202. package/dist/pool.race.d.ts +65 -0
  203. package/dist/pool.race.js +140 -0
  204. package/dist/pool.replay.d.ts +46 -0
  205. package/dist/pool.replay.js +127 -0
  206. package/dist/pool.section.d.ts +13 -0
  207. package/dist/pool.section.js +83 -0
  208. package/dist/pool.style.d.ts +20 -0
  209. package/dist/pool.style.js +169 -0
  210. package/dist/pool.types.d.ts +145 -0
  211. package/dist/pool.types.js +3 -0
  212. package/dist/pool.words.d.ts +13 -0
  213. package/dist/pool.words.js +101 -0
  214. package/dist/ranges.names.js +53 -3
  215. package/dist/replay-entry.d.ts +3 -0
  216. package/dist/replay-entry.js +2 -0
  217. package/dist/restyle.js +1 -1
  218. package/dist/road.draw.js +3 -2
  219. package/dist/road.js +2 -1
  220. package/dist/road.types.d.ts +3 -0
  221. package/dist/rules.d.ts +138 -0
  222. package/dist/rules.js +511 -0
  223. package/dist/rules.types.d.ts +4 -0
  224. package/dist/rules.types.js +64 -0
  225. package/dist/score.d.ts +3 -0
  226. package/dist/score.js +93 -6
  227. package/dist/sheet.d.ts +3 -0
  228. package/dist/sheet.js +7 -3
  229. package/dist/situation.d.ts +135 -0
  230. package/dist/situation.draw.d.ts +34 -0
  231. package/dist/situation.draw.js +202 -0
  232. package/dist/situation.js +337 -0
  233. package/dist/situation.style.d.ts +2 -0
  234. package/dist/situation.style.js +45 -0
  235. package/dist/situation.types.d.ts +77 -0
  236. package/dist/situation.types.js +3 -0
  237. package/dist/situation.widgets.d.ts +39 -0
  238. package/dist/situation.widgets.js +129 -0
  239. package/dist/skating/describe.d.ts +7 -0
  240. package/dist/skating/describe.js +44 -0
  241. package/dist/skating/events.d.ts +24 -0
  242. package/dist/skating/events.js +47 -0
  243. package/dist/skating/figure.d.ts +24 -0
  244. package/dist/skating/figure.js +37 -0
  245. package/dist/skating/long.d.ts +54 -0
  246. package/dist/skating/long.js +111 -0
  247. package/dist/skating/parts.d.ts +43 -0
  248. package/dist/skating/parts.js +40 -0
  249. package/dist/skating/plan.d.ts +55 -0
  250. package/dist/skating/plan.js +197 -0
  251. package/dist/skating/short.d.ts +47 -0
  252. package/dist/skating/short.js +89 -0
  253. package/dist/skating/track.d.ts +66 -0
  254. package/dist/skating/track.js +94 -0
  255. package/dist/skating/types.d.ts +57 -0
  256. package/dist/skating/types.js +3 -0
  257. package/dist/skating-entry.d.ts +17 -0
  258. package/dist/skating-entry.js +11 -0
  259. package/dist/skating.style.d.ts +4 -0
  260. package/dist/skating.style.js +24 -0
  261. package/dist/strings.d.ts +470 -0
  262. package/dist/strings.js +674 -13
  263. package/dist/style.d.ts +2 -0
  264. package/dist/style.js +19 -2
  265. package/dist/surfaces/artistic.d.ts +9 -0
  266. package/dist/surfaces/artistic.js +94 -0
  267. package/dist/surfaces/athletics.d.ts +16 -0
  268. package/dist/surfaces/athletics.js +132 -0
  269. package/dist/surfaces/baseball.js +17 -0
  270. package/dist/surfaces/basketball.floor.d.ts +27 -0
  271. package/dist/surfaces/basketball.floor.js +83 -0
  272. package/dist/surfaces/basketball.gear.d.ts +27 -0
  273. package/dist/surfaces/basketball.gear.js +90 -0
  274. package/dist/surfaces/basketball.js +44 -22
  275. package/dist/surfaces/budo.d.ts +6 -0
  276. package/dist/surfaces/budo.js +104 -0
  277. package/dist/surfaces/curling.d.ts +16 -0
  278. package/dist/surfaces/curling.fold.d.ts +67 -0
  279. package/dist/surfaces/curling.fold.js +107 -0
  280. package/dist/surfaces/curling.js +37 -3
  281. package/dist/surfaces/dive.d.ts +9 -0
  282. package/dist/surfaces/dive.js +128 -0
  283. package/dist/surfaces/field.d.ts +7 -2
  284. package/dist/surfaces/field.js +15 -9
  285. package/dist/surfaces/football.js +7 -0
  286. package/dist/surfaces/hockey.js +4 -2
  287. package/dist/surfaces/net.d.ts +2 -1
  288. package/dist/surfaces/net.js +160 -15
  289. package/dist/surfaces/polo.d.ts +12 -0
  290. package/dist/surfaces/polo.js +159 -0
  291. package/dist/surfaces/pool.d.ts +27 -0
  292. package/dist/surfaces/pool.js +198 -0
  293. package/dist/surfaces/skating.d.ts +6 -0
  294. package/dist/surfaces/skating.js +62 -0
  295. package/dist/surfaces/soccer.js +2 -1
  296. package/dist/surfaces/surface.d.ts +76 -0
  297. package/dist/surfaces/venue.d.ts +15 -0
  298. package/dist/surfaces/venue.js +95 -0
  299. package/dist/target-entry.d.ts +2 -0
  300. package/dist/target-entry.js +2 -0
  301. package/dist/target.d.ts +200 -0
  302. package/dist/target.js +525 -0
  303. package/dist/team.common.d.ts +1 -1
  304. package/dist/team.common.js +3 -3
  305. package/dist/team.formation.d.ts +3 -1
  306. package/dist/team.formation.js +3 -3
  307. package/dist/team.layers.d.ts +2 -2
  308. package/dist/team.layers.js +4 -1
  309. package/dist/team.lineup.d.ts +27 -0
  310. package/dist/team.lineup.js +207 -0
  311. package/dist/team.network.js +6 -5
  312. package/dist/team.shape.js +5 -5
  313. package/dist/team.types.d.ts +40 -1
  314. package/dist/tenants.d.ts +77 -0
  315. package/dist/tenants.data.d.ts +8 -0
  316. package/dist/tenants.data.js +1793 -0
  317. package/dist/tenants.js +46 -0
  318. package/dist/turn-entry.d.ts +12 -0
  319. package/dist/turn-entry.js +7 -0
  320. package/dist/turn.camera.d.ts +116 -0
  321. package/dist/turn.camera.js +184 -0
  322. package/dist/turn.dom.d.ts +40 -0
  323. package/dist/turn.dom.js +353 -0
  324. package/dist/turn.kit.d.ts +86 -0
  325. package/dist/turn.kit.js +110 -0
  326. package/dist/turn.markup.d.ts +48 -0
  327. package/dist/turn.markup.js +108 -0
  328. package/dist/turn.model.d.ts +78 -0
  329. package/dist/turn.model.js +91 -0
  330. package/dist/turn.style.d.ts +5 -0
  331. package/dist/turn.style.js +56 -0
  332. package/dist/types.d.ts +221 -20
  333. package/dist/units.d.ts +1 -1
  334. package/dist/units.js +22 -1
  335. package/dist/uprights.board.d.ts +17 -0
  336. package/dist/uprights.board.js +59 -0
  337. package/dist/uprights.budo.d.ts +17 -0
  338. package/dist/uprights.budo.js +87 -0
  339. package/dist/uprights.d.ts +37 -0
  340. package/dist/uprights.fields.d.ts +32 -0
  341. package/dist/uprights.fields.js +172 -0
  342. package/dist/uprights.goal.d.ts +49 -0
  343. package/dist/uprights.goal.js +69 -0
  344. package/dist/uprights.js +169 -0
  345. package/dist/uprights.more.d.ts +7 -0
  346. package/dist/uprights.more.js +183 -0
  347. package/dist/uprights.net.d.ts +12 -0
  348. package/dist/uprights.net.js +109 -0
  349. package/dist/uprights.netkit.d.ts +28 -0
  350. package/dist/uprights.netkit.js +67 -0
  351. package/dist/uprights.pools.d.ts +8 -0
  352. package/dist/uprights.pools.js +190 -0
  353. package/dist/uprights.rinks.d.ts +27 -0
  354. package/dist/uprights.rinks.js +106 -0
  355. package/dist/uprights.track.d.ts +50 -0
  356. package/dist/uprights.track.js +246 -0
  357. package/dist/version.d.ts +1 -1
  358. package/dist/version.js +1 -1
  359. package/dist/zones-entry.d.ts +2 -0
  360. package/dist/zones-entry.js +2 -0
  361. package/package.json +56 -3
@@ -0,0 +1,166 @@
1
+ // The standard stadium's field events, each in its usual place (Track and Field Facilities Manual 2019, 2.5, Figure 2.5a "Standard layout of competition facility", and the Marking Plan for the 400 m
2
+ // Standard Track, Figure 2.2.1.6a, at 1:350): the pole vaults and the shot put circles in the first segment, the discus and hammer circle, the high jumps and the other shot put in the second, a
3
+ // javelin runway through the middle of each, and the long and triple jumps beyond the back straight. The places are read off the Marking Plan to the metre, which is the precision of its scale; the
4
+ // sizes of everything are the Manual's and the Rules'. Metres, in the frame of track.ts.
5
+ import { line } from "../fields.kit.js";
6
+ import { num } from "../format.js";
7
+ import { bounds, cageShapes, circleParts, highJumpParts, javelinParts, pitParts, poleVaultEnd, rectArea, runwayLines, sectorShapes, stopBoard, takeOffBoard, } from "./facilities.js";
8
+ import { addParts, emptyParts } from "./oval.js";
9
+ /** The sectors' lengths (Manual 2.1.1.3 and Figures 2.4.1.1, 2.4.2.1, 2.4.3.1, 2.4.4.1): the shot's 25 m, the discus's 80 m, the hammer's 90 m, the javelin's 100 m. */
10
+ export const SECTOR_REACH = { "shot-put": 25, "discus-throw": 80, "hammer-throw": 90, "javelin-throw": 100 };
11
+ /** Where the standard stadium puts each facility, in metres from the centre of the semicircle of its segment (CP1 at the left, CP2 at the right), read from the Marking Plan. */
12
+ export const ARENA = {
13
+ /** The synthetic surface of a segment ends, and the turf of the infield begins, this far from the semicircle's centre along the straights' axis (Marking Plan; 108.39 m of turf between: a 105 m pitch fits). */
14
+ turf: 12,
15
+ /** The javelin arc's apex is this far beyond the segment's centre; the centre point is 8 m behind it. */
16
+ javelinApex: 55.1 - 42.195,
17
+ /** The shot put circles: from the segment's centre outward along the axis, and the distance up or down. */
18
+ shotWest: { out: 13.5, across: 18.15 },
19
+ shotEast: { out: 14.2, across: 18.5 },
20
+ /** The combined discus and hammer circle of the second segment. */
21
+ discus: { out: 20.4, across: -24.1, heading: Math.PI * (1 - 0.097) },
22
+ /** The two pole vault runways of the first segment: their middle lines, the boxes' places and the length, from the axis. */
23
+ vaultA: { out: 23.26, box: 16.5 },
24
+ vaultB: { out: 15.82, box: 20.7 },
25
+ vaultReach: 26,
26
+ /** The high jumps: the bar's distance beyond the segment's centre and the distance of each from the axis (the spacing of two sets of uprights is 12 to 15 m: 13.5 m). */
27
+ highJump: { out: 15, across: 6.75 },
28
+ /** The long and triple jump beyond the back straight (Figure 2.5a, Marking Plan): the strip, the two runways' middle lines, and the pits' places along the straight. */
29
+ strip: { x0: -45.6, x1: 46.2, y0: -56.6 },
30
+ rows: [
31
+ { y: -54.2, west: [-39.7, -31.7], east: [23, 31.1] },
32
+ { y: -50.4, west: [-30.9, -22.9], east: [31.9, 40] },
33
+ ],
34
+ };
35
+ const rad = (deg) => (deg * Math.PI) / 180;
36
+ void rad;
37
+ /** The standard stadium's field events, those asked for. */
38
+ export function infieldParts(o, events) {
39
+ const parts = emptyParts();
40
+ const facilities = [];
41
+ const S = o.straight;
42
+ const cp1x = -S / 2;
43
+ const cp2x = S / 2;
44
+ const has = (e) => events.has(e);
45
+ // The javelin: a runway through the middle of each segment, thrown towards the middle of the infield.
46
+ if (has("javelin-throw")) {
47
+ const apex = ARENA.javelinApex;
48
+ for (const [id, cx, heading] of [
49
+ ["javelin-west", cp1x - apex - 8 + 0, 0],
50
+ ["javelin-east", cp2x + apex + 8, Math.PI],
51
+ ]) {
52
+ // The centre point is 8 m behind the arc's apex, so beyond the segment's centre by `apex + 8` on its own side.
53
+ const made = javelinParts(id, [id === "javelin-west" ? cp1x - apex - 8 : cx, 0], heading);
54
+ addParts(parts, made.parts);
55
+ facilities.push(made.facility);
56
+ }
57
+ }
58
+ // The shot put: two circles in the first segment, throwing to the east, and one in the second, throwing to the west.
59
+ if (has("shot-put")) {
60
+ const circles = [
61
+ ["shot-west-north", [cp1x - ARENA.shotWest.out, -ARENA.shotWest.across], 0],
62
+ ["shot-west-south", [cp1x - ARENA.shotWest.out, ARENA.shotWest.across], 0],
63
+ ["shot-east-south", [cp2x + ARENA.shotEast.out, ARENA.shotEast.across], Math.PI],
64
+ ];
65
+ for (const [id, c, heading] of circles) {
66
+ addParts(parts, circleParts(id, "shot-put", c, heading, 2.135));
67
+ parts.areas.push(stopBoard(id, c, heading, 2.135));
68
+ parts.shapes.push(...sectorShapes(id, "shot-put", c, heading, 1.0675, SECTOR_REACH["shot-put"]));
69
+ const reach = SECTOR_REACH["shot-put"];
70
+ facilities.push({ id, event: "shot-put", x: c[0], y: c[1], heading, reach, box: bounds([c, [c[0] + Math.cos(heading) * reach, c[1] + Math.sin(heading) * reach + reach * 0.31], [c[0] + Math.cos(heading) * reach, c[1] + Math.sin(heading) * reach - reach * 0.31]]) });
71
+ }
72
+ }
73
+ // The discus and the hammer: one circle and cage in the second segment, near the 1500 m start, throwing across the infield.
74
+ if (has("discus-throw") || has("hammer-throw")) {
75
+ const c = [cp2x + ARENA.discus.out, ARENA.discus.across];
76
+ const heading = ARENA.discus.heading;
77
+ const both = has("discus-throw") && has("hammer-throw");
78
+ // A circle of 2.50 m, reduced to 2.135 m for the hammer by a ring inside it (Rule 32, throwing circle): both are drawn when both events are.
79
+ addParts(parts, circleParts("discus-hammer", has("discus-throw") ? "discus-throw" : "hammer-throw", c, heading, has("discus-throw") ? 2.5 : 2.135));
80
+ if (both)
81
+ parts.shapes.push(...circleParts("hammer-insert", "hammer-throw", c, heading, 2.135).shapes.filter((s) => s.kind === "ring"));
82
+ parts.shapes.push(...cageShapes("discus-hammer", c, heading));
83
+ const reach = has("hammer-throw") ? SECTOR_REACH["hammer-throw"] : SECTOR_REACH["discus-throw"];
84
+ parts.shapes.push(...sectorShapes("discus-hammer", has("discus-throw") ? "discus-throw" : "hammer-throw", c, heading, has("discus-throw") ? 1.25 : 1.0675, reach));
85
+ if (both) {
86
+ // The discus's shorter arc across the same sector.
87
+ const half = Math.asin(0.3);
88
+ const a = heading - half;
89
+ const b = heading + half;
90
+ const r = SECTOR_REACH["discus-throw"];
91
+ const p = [c[0] + r * Math.cos(a), c[1] + r * Math.sin(a)];
92
+ const q = [c[0] + r * Math.cos(b), c[1] + r * Math.sin(b)];
93
+ parts.shapes.push({ kind: "path", id: "discus-sector-arc", feature: "discus-throw", d: `M${num(p[0])} ${num(p[1])}A${num(r)} ${num(r)} 0 0 1 ${num(q[0])} ${num(q[1])}` });
94
+ }
95
+ const end = [c[0] + Math.cos(heading) * reach, c[1] + Math.sin(heading) * reach];
96
+ for (const event of ["discus-throw", "hammer-throw"])
97
+ if (has(event))
98
+ facilities.push({ id: event === "discus-throw" ? "discus" : "hammer", event, x: c[0], y: c[1], heading, reach: SECTOR_REACH[event], box: bounds([c, [end[0], end[1] + 0.31 * reach], [end[0], end[1] - 0.31 * reach], [c[0] - 5, c[1] - 5], [c[0] + 8, c[1] + 8]]) });
99
+ }
100
+ // The high jump: two, symmetrical about the javelin runway of the second segment, the athletes running up from the track and jumping towards the middle.
101
+ if (has("high-jump")) {
102
+ for (const [id, side] of [["high-jump-north", -1], ["high-jump-south", 1]]) {
103
+ const made = highJumpParts(id, [cp2x + ARENA.highJump.out, side * ARENA.highJump.across], Math.PI);
104
+ addParts(parts, made.parts);
105
+ facilities.push(made.facility);
106
+ }
107
+ }
108
+ // The pole vault: two runways in the first segment, each with a box and a mat at both ends, and the runway cut where the javelin's crosses it.
109
+ if (has("pole-vault")) {
110
+ for (const [name, v] of [["pole-vault-a", ARENA.vaultA], ["pole-vault-b", ARENA.vaultB]]) {
111
+ const x = cp1x - v.out;
112
+ const reach = ARENA.vaultReach;
113
+ const gap = has("javelin-throw") ? 2.1 : 0;
114
+ for (const side of [-1, 1]) {
115
+ const lo = side === -1 ? -reach : gap;
116
+ const hi = side === -1 ? -gap : reach;
117
+ parts.shapes.push(...runwayLines(`${name}-${side}`, "pole-vault", [x, lo], [x, hi]));
118
+ }
119
+ for (const side of [-1, 1]) {
120
+ const made = poleVaultEnd(`${name}-${side === -1 ? "north" : "south"}`, [x, side * v.box], side === -1 ? -Math.PI / 2 : Math.PI / 2);
121
+ // The vaulter runs towards the box from the far end, so the box's 0-line faces the mat beyond it, away from the runway's middle.
122
+ addParts(parts, made.parts);
123
+ facilities.push(made.facility);
124
+ }
125
+ }
126
+ }
127
+ // The long and the triple jump, beyond the back straight: two runways in a strip, each with a pit at either end, a take-off board for each run.
128
+ if (has("long-jump") || has("triple-jump")) {
129
+ const strip = { id: "jump-strip", feature: "track", cls: "ky-ath-track", d: `M${num(ARENA.strip.x0)} ${num(ARENA.strip.y0)}H${num(ARENA.strip.x1)}V${num(-o.radius - o.lanes * o.lane + 0.3)}H${num(ARENA.strip.x0)}Z` };
130
+ parts.areas.push(strip);
131
+ const boxes = [];
132
+ for (const [r, row] of ARENA.rows.entries()) {
133
+ const west = row.west;
134
+ const east = row.east;
135
+ // The runway between the pits' near ends, and across both to the pits' far ends so that it reads as one facility with a pit at either end.
136
+ parts.shapes.push(...runwayLines(`jump-${r}`, has("long-jump") ? "long-jump" : "triple-jump", [west[1], row.y], [east[0], row.y]));
137
+ for (const [pit, edge, heading, name] of [
138
+ [west, west[1], Math.PI, "west"],
139
+ [east, east[0], 0, "east"],
140
+ ]) {
141
+ const id = `jump-${r}-${name}`;
142
+ const event = has("long-jump") ? "long-jump" : "triple-jump";
143
+ addParts(parts, pitParts(id, event, [(pit[0] + pit[1]) / 2, row.y], 0, pit[1] - pit[0], 3));
144
+ const jumpHeading = heading;
145
+ // The athlete runs towards the pit: for the west pit that is westward, so the board is east of the pit's near end (the east edge), and the run comes from the east.
146
+ const near = [edge, row.y];
147
+ if (has("long-jump"))
148
+ parts.areas.push(takeOffBoard(`${id}-lj-board`, "long-jump", near, jumpHeading + 0, 3));
149
+ if (has("triple-jump")) {
150
+ parts.areas.push(takeOffBoard(`${id}-tj-board-men`, "triple-jump", near, jumpHeading, 13), takeOffBoard(`${id}-tj-board-women`, "triple-jump", near, jumpHeading, 11));
151
+ }
152
+ boxes.push({ x0: pit[0] - 1, x1: pit[1] + 1, y0: row.y - 2, y1: row.y + 2 });
153
+ // One facility for each of the two events that jump into this pit, the pit's near end being its place.
154
+ for (const e of ["long-jump", "triple-jump"])
155
+ if (has(e))
156
+ facilities.push({ id, event: e, x: edge, y: row.y, heading: jumpHeading, reach: 45, box: { x0: Math.min(pit[0], pit[1]) - 1, x1: Math.max(pit[0], pit[1]) + 1, y0: row.y - 2.5, y1: row.y + 2.5 } });
157
+ }
158
+ }
159
+ void boxes;
160
+ }
161
+ void line;
162
+ void rectArea;
163
+ return { parts, facilities };
164
+ }
165
+ /** The strip beyond the back straight where the long and the triple jumps are, as a box, when they are drawn. */
166
+ export const jumpStrip = () => ({ x0: ARENA.strip.x0, y0: ARENA.strip.y0, x1: ARENA.strip.x1, y1: -46 });
@@ -0,0 +1,13 @@
1
+ import { type Facility } from "./facilities.ts";
2
+ import { type Parts } from "./oval.ts";
3
+ import type { MBox, MMark } from "./plan.ts";
4
+ import type { AthleticsFieldEvent } from "./types.ts";
5
+ /** What a field event alone is: its shapes, its facility as data, the box round it and the parts to label. */
6
+ export interface Layout {
7
+ parts: Parts;
8
+ facility: Facility;
9
+ box: MBox;
10
+ marks: MMark[];
11
+ }
12
+ /** The layout of one field event alone. */
13
+ export declare function layoutOf(event: AthleticsFieldEvent): Layout;
@@ -0,0 +1,98 @@
1
+ // One field event alone, at a large scale, from the diagram of its facility (Track and Field Facilities Manual 2019, Figures 2.3.1.1a, 2.3.2.1, 2.3.3.1, 2.3.4.1, 2.4.1.1 to 2.4.4.2; Technical Rules 25 to 38 of
2
+ // Book C2.1): the athlete throws or jumps to the right, from a point at the origin (a circle's centre, a javelin arc's centre point, a jump's take-off line, the bar, the vault's zero line). Metres.
3
+ import { line } from "../fields.kit.js";
4
+ import { num } from "../format.js";
5
+ import { bounds, cageShapes, circleParts, highJumpParts, javelinParts, pitParts, poleVaultEnd, runwayLines, sectorShapes, stopBoard, takeOffBoard, SECTOR_ANGLE, } from "./facilities.js";
6
+ import { addParts, emptyParts } from "./oval.js";
7
+ import { SECTOR_REACH } from "./infield.js";
8
+ const O = [0, 0];
9
+ /** The landing sector as ground: mown grass between the sector lines from `rim` out to the arc (a circle's rim, or a javelin arc's). */
10
+ function sectorGrass(id, event, reach, half, rim = 0) {
11
+ const at = (k, a) => `${num(k * Math.cos(a))} ${num(k * Math.sin(a))}`;
12
+ return { id: `${id}-sector-ground`, feature: event, cls: "ky-ath-grass", d: `M${at(rim, -half)}L${at(reach, -half)}A${num(reach)} ${num(reach)} 0 0 1 ${at(reach, half)}L${at(rim, half)}Z` };
13
+ }
14
+ /** A runway as ground: the track's own surface, `width` wide from `x0` to `x1`. */
15
+ function runwayGround(id, event, x0, x1, width) {
16
+ return { id: `${id}-runway-ground`, feature: event, cls: "ky-ath-track", d: `M${num(x0)} ${num(-width / 2)}H${num(x1)}V${num(width / 2)}H${num(x0)}Z` };
17
+ }
18
+ /** The long jump's and the triple jump's facility: the runway 45 m long (Rule 29; Manual 2.3.1.2), the take-off boards, the landing area 3 m wide and 8 m long. */
19
+ function jumpLayout(event) {
20
+ const parts = emptyParts();
21
+ parts.areas.push(runwayGround(event, event, -45, event === "long-jump" ? 3 : 13, 1.22));
22
+ // The pit: 8 m long, 3 m wide, its near end 3 m past the long jump's take-off line (Manual 2.3.1.4) or 13 m past the men's triple jump line (Rule 31: not less than 13 m for men, 11 for women).
23
+ const near = event === "long-jump" ? 3 : 13;
24
+ const len = 8;
25
+ addParts(parts, pitParts(event, event, [near + len / 2, 0], 0, len, 3));
26
+ parts.shapes.push(...runwayLines(event, event, [-45, 0], [near + len, 0]));
27
+ parts.areas.push(takeOffBoard(`${event}-board`, event, [near, 0], 0, near));
28
+ if (event === "triple-jump")
29
+ parts.areas.push(takeOffBoard(`${event}-board-women`, event, [near, 0], 0, 11));
30
+ // The window shows the last 24 m of the runway: the rest runs off its edge.
31
+ const box = { x0: -24, y0: -3.2, x1: near + len + 2, y1: 3.2 };
32
+ const facility = { id: event, event, x: 0, y: 0, heading: 0, box, reach: 45 };
33
+ const marks = [
34
+ { id: "runway", x: -25, y: -0.61, side: "top" },
35
+ { id: "take-off-board", x: -0.1, y: 0.6, side: "bottom" },
36
+ { id: "landing-area", x: near + len / 2, y: -1.5, side: "top" },
37
+ ];
38
+ return { parts, facility, box, marks };
39
+ }
40
+ /** The throws: a circle with its sector and, for the discus and the hammer, the cage; the shot's stop board. */
41
+ function throwLayout(event) {
42
+ const parts = emptyParts();
43
+ const d = event === "discus-throw" ? 2.5 : 2.135;
44
+ const reach = SECTOR_REACH[event];
45
+ parts.areas.push(sectorGrass(event, event, reach, SECTOR_ANGLE / 2));
46
+ addParts(parts, circleParts(event, event, O, 0, d));
47
+ if (event === "shot-put")
48
+ parts.areas.push(stopBoard(event, O, 0, d));
49
+ else
50
+ parts.shapes.push(...cageShapes(event, O, 0));
51
+ parts.shapes.push(...sectorShapes(event, event, O, 0, d / 2, reach));
52
+ const half = SECTOR_ANGLE / 2;
53
+ const box = { x0: -8, y0: -reach * Math.sin(half) - 2, x1: reach + 2, y1: reach * Math.sin(half) + 2 };
54
+ const facility = { id: event, event, x: 0, y: 0, heading: 0, box, reach };
55
+ const marks = [
56
+ { id: "throwing-circle", x: 0, y: -d / 2 - 0.6, side: "top" },
57
+ { id: "sector", x: reach * 0.5, y: -reach * 0.5 * Math.tan(half), side: "top" },
58
+ ];
59
+ if (event === "shot-put")
60
+ marks.push({ id: "stop-board", x: d / 2, y: d / 2 + 0.5, side: "bottom" });
61
+ else
62
+ marks.push({ id: "cage", x: 7, y: -3, side: "top" });
63
+ return { parts, facility, box, marks };
64
+ }
65
+ /** The layout of one field event alone. */
66
+ export function layoutOf(event) {
67
+ switch (event) {
68
+ case "long-jump":
69
+ case "triple-jump":
70
+ return jumpLayout(event);
71
+ case "shot-put":
72
+ case "discus-throw":
73
+ case "hammer-throw":
74
+ return throwLayout(event);
75
+ case "javelin-throw": {
76
+ const made = javelinParts("javelin", O, 0);
77
+ const half = Math.asin(2 / 8);
78
+ made.parts.areas.unshift(runwayGround("javelin", "javelin-throw", -36.5 + 8 * Math.cos(half), 8 * Math.cos(half), 4), sectorGrass("javelin", "javelin-throw", 100, half, 8));
79
+ const box = { x0: -18, y0: -100 * Math.sin(half) - 2, x1: 102, y1: 100 * Math.sin(half) + 2 };
80
+ return { parts: made.parts, facility: made.facility, box, marks: [{ id: "runway", x: -20, y: -2.1, side: "top" }, { id: "throwing-arc", x: 8, y: -1.5, side: "top" }, { id: "sector", x: 50, y: -50 * Math.tan(half), side: "top" }] };
81
+ }
82
+ case "high-jump": {
83
+ const made = highJumpParts("high-jump", O, 0);
84
+ made.parts.areas.unshift({ id: "high-jump-runway-ground", feature: "high-jump", cls: "ky-ath-track", d: `M0 -8H${num(-Math.sqrt(15 * 15 - 64))}A15 15 0 0 0 ${num(-Math.sqrt(15 * 15 - 64))} 8H0Z` });
85
+ const box = made.facility.box;
86
+ return { parts: made.parts, facility: made.facility, box: { x0: box.x0 - 1, y0: box.y0 - 1, x1: box.x1 + 1, y1: box.y1 + 1 }, marks: [{ id: "crossbar", x: 0, y: -2, side: "top" }, { id: "landing-mat", x: 1.5, y: 3.2, side: "bottom" }, { id: "run-up", x: -9, y: -8, side: "top" }] };
87
+ }
88
+ default: {
89
+ // The pole vault: a runway of 45 m to the box, the box, the zero line and the mat beyond.
90
+ const made = poleVaultEnd("pole-vault", O, 0);
91
+ made.parts.areas.unshift(runwayGround("pole-vault", "pole-vault", -45, 0, 1.22));
92
+ made.parts.shapes.push(...runwayLines("pole-vault", "pole-vault", [-45, 0], [0, 0]));
93
+ made.parts.shapes.push(line("pole-vault-runway-end", "pole-vault", -45, -0.61, -45, 0.61, { w: 0.05 }));
94
+ const box = bounds([[-24, -3.5], [9, 3.5]]);
95
+ return { parts: made.parts, facility: made.facility, box, marks: [{ id: "runway", x: -25, y: -0.61, side: "top" }, { id: "zero-line", x: 0, y: -2.9, side: "top" }, { id: "landing-mat", x: 4.2, y: 3.1, side: "bottom" }, { id: "box", x: -0.5, y: 0.5, side: "bottom" }] };
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,57 @@
1
+ import type { Area, Shape } from "../fields.types.ts";
2
+ import type { AthleticsFigures } from "../leagues/athletics.ts";
3
+ import { type Oval } from "./track.ts";
4
+ /** A string of lane numbers painted on the track: the digits, how tall, where they are centred. They stand upright whatever way the page is turned. */
5
+ export interface Digits {
6
+ id: string;
7
+ feature: string;
8
+ text: string;
9
+ x: number;
10
+ y: number;
11
+ h: number;
12
+ /** Drawn on a disc of the plate's colour, in the plate's ink, at a size that reads in a close-up (a tag), not painted on the track. */
13
+ tag?: boolean;
14
+ /** For a number behind a start line: the point of the line in this lane and the unit vector the athlete runs along, so that a tag can be moved back to clear the line. */
15
+ from?: readonly [x: number, y: number, fx: number, fy: number];
16
+ }
17
+ /** What a part of a plan adds: shapes and areas in painter's order, and digits. */
18
+ export interface Parts {
19
+ areas: Area[];
20
+ shapes: Shape[];
21
+ digits: Digits[];
22
+ }
23
+ export declare const emptyParts: () => Parts;
24
+ /** Add `more` to `into`. */
25
+ export declare function addParts(into: Parts, more: Parts): void;
26
+ /** The path of a stadium: two semicircles of radius `r` joined by straights of length `s`, about the origin. */
27
+ export declare const stadiumD: (s: number, r: number) => string;
28
+ /**
29
+ * A lane line of the oval, cut where the straight's surface lies over its bends (the straight runs on beyond the oval's, and the Marking Plan draws only the straight's own lines there): the bottom
30
+ * straight between the bends, the east bend from where it leaves the straight's run-out round to the top, the top straight, and the west bend as far as the straight's starting area.
31
+ */
32
+ export declare function laneLineD(o: Oval, r: number, straight: StraightPlan | undefined): string;
33
+ /** The radius of the outer edge of an oval's last lane. */
34
+ export declare const outerRadius: (o: Oval) => number;
35
+ /** The straight's geometry: its first and last x (the starting area before the longest race, the run-out beyond the finish line), its lanes and how wide each is. */
36
+ export interface StraightPlan {
37
+ lanes: number;
38
+ lane: number;
39
+ x0: number;
40
+ x1: number;
41
+ /** The start of the longest race of the straight, in metres before the finish line. */
42
+ longest: number;
43
+ /** The straight's inside edge (the top of lane 1) and its finish line, in the plan's frame: the oval's finish straight runs on, the covered track's lies inside it. */
44
+ y0: number;
45
+ finish: number;
46
+ }
47
+ /** The straight that runs on beyond the oval's finish straight (Manual 2.2.2.1): at least six lanes, a starting area of 3 m before its longest race and a run-out of 17 m. */
48
+ export declare function straightOf(o: Oval, fig: AthleticsFigures, lanes: number, longest: number): StraightPlan;
49
+ /**
50
+ * The straight of a covered track (Rules 41 to 43; the Marking Plan for the Standard Short Track): lanes 1.22 m wide inside the oval, parallel to its straights, with a starting area of 3 m before a
51
+ * 60 m start line and a run-out beyond the finish line. Its place in the infield is ours: the Rules and the plan give its lanes and its length, not where it lies.
52
+ */
53
+ export declare function indoorStraightOf(o: Oval, fig: AthleticsFigures, lanes: number, length: number): StraightPlan;
54
+ /** The infield straight of a covered track: its surface, its lane lines, its start area's and run-out's ends and its finish line, and the lane numbers before the finish. */
55
+ export declare function indoorStraightParts(st: StraightPlan, numbers: boolean, w: number): Parts;
56
+ /** The surface of the oval and of the straight, the kerb, the lane lines, the finish line and the numbers before it. */
57
+ export declare function ovalParts(o: Oval, fig: AthleticsFigures, straight: StraightPlan | undefined, numbers: boolean, hole?: string): Parts;
@@ -0,0 +1,116 @@
1
+ // The oval, the straight that runs on beyond it and the finish: the surface of the track between its kerb and its outer edge, the lane lines, the kerb, the finish line and the lane numbers
2
+ // before it. Every figure is the Track and Field Facilities Manual's (2019 edition, 2.2.1 and 2.2.2) or Technical Rule 14's of Book C2.1, in metres. Nothing here draws SVG: it makes the shapes.
3
+ import { line, path } from "../fields.kit.js";
4
+ import { num } from "../format.js";
5
+ import { laneEdge } from "./track.js";
6
+ export const emptyParts = () => ({ areas: [], shapes: [], digits: [] });
7
+ /** Add `more` to `into`. */
8
+ export function addParts(into, more) {
9
+ into.areas.push(...more.areas);
10
+ into.shapes.push(...more.shapes);
11
+ into.digits.push(...more.digits);
12
+ }
13
+ /** The path of a stadium: two semicircles of radius `r` joined by straights of length `s`, about the origin. */
14
+ export const stadiumD = (s, r) => `M${num(-s / 2)} ${num(-r)}H${num(s / 2)}A${num(r)} ${num(r)} 0 0 1 ${num(s / 2)} ${num(r)}H${num(-s / 2)}A${num(r)} ${num(r)} 0 0 1 ${num(-s / 2)} ${num(-r)}Z`;
15
+ /**
16
+ * A lane line of the oval, cut where the straight's surface lies over its bends (the straight runs on beyond the oval's, and the Marking Plan draws only the straight's own lines there): the bottom
17
+ * straight between the bends, the east bend from where it leaves the straight's run-out round to the top, the top straight, and the west bend as far as the straight's starting area.
18
+ */
19
+ export function laneLineD(o, r, straight) {
20
+ if (straight === undefined)
21
+ return stadiumD(o.straight, r);
22
+ const S = o.straight;
23
+ const R = o.radius;
24
+ const wEast = straight.x1 - S / 2;
25
+ const wWest = -S / 2 - straight.x0;
26
+ // East bend, from the bottom (f = 0): inside the straight while its depth below the kerb line is positive and it is no further out than the run-out.
27
+ const fEast = Math.min(Math.acos(Math.min(1, R / r)), Math.asin(Math.min(1, wEast / r)));
28
+ // West bend, from the top: inside the straight from where it comes back below the kerb line and within the starting area.
29
+ const fWest = Math.max(Math.PI - Math.acos(Math.min(1, R / r)), Math.PI - Math.asin(Math.min(1, wWest / r)));
30
+ const e = [S / 2 + r * Math.sin(fEast), r * Math.cos(fEast)];
31
+ const w = [-S / 2 - r * Math.sin(fWest), -r * Math.cos(fWest)];
32
+ return `M${num(e[0])} ${num(e[1])}A${num(r)} ${num(r)} 0 0 0 ${num(S / 2)} ${num(-r)}H${num(-S / 2)}A${num(r)} ${num(r)} 0 0 0 ${num(w[0])} ${num(w[1])}M${num(-S / 2)} ${num(r)}H${num(S / 2)}`;
33
+ }
34
+ /** The radius of the outer edge of an oval's last lane. */
35
+ export const outerRadius = (o) => laneEdge(o, o.lanes);
36
+ /** The straight that runs on beyond the oval's finish straight (Manual 2.2.2.1): at least six lanes, a starting area of 3 m before its longest race and a run-out of 17 m. */
37
+ export function straightOf(o, fig, lanes, longest) {
38
+ return { lanes, lane: fig.straightLane, x0: o.straight / 2 - longest - fig.startArea, x1: o.straight / 2 + fig.runOut, longest, y0: o.radius, finish: o.straight / 2 };
39
+ }
40
+ /**
41
+ * The straight of a covered track (Rules 41 to 43; the Marking Plan for the Standard Short Track): lanes 1.22 m wide inside the oval, parallel to its straights, with a starting area of 3 m before a
42
+ * 60 m start line and a run-out beyond the finish line. Its place in the infield is ours: the Rules and the plan give its lanes and its length, not where it lies.
43
+ */
44
+ export function indoorStraightOf(o, fig, lanes, length) {
45
+ const total = fig.startArea + length + fig.runOut;
46
+ const x0 = -total / 2;
47
+ const width = lanes * fig.straightLane;
48
+ return { lanes, lane: fig.straightLane, x0, x1: x0 + total, longest: length, y0: -width / 2, finish: x0 + fig.startArea + length };
49
+ }
50
+ /** The infield straight of a covered track: its surface, its lane lines, its start area's and run-out's ends and its finish line, and the lane numbers before the finish. */
51
+ export function indoorStraightParts(st, numbers, w) {
52
+ const parts = emptyParts();
53
+ const edge = st.y0 + st.lanes * st.lane;
54
+ parts.areas.push({ id: "infield-straight", feature: "track", cls: "ky-ath-track", d: `M${num(st.x0)} ${num(st.y0)}H${num(st.x1)}V${num(edge)}H${num(st.x0)}Z` });
55
+ for (let k = 0; k <= st.lanes; k += 1) {
56
+ const y = k === 0 ? st.y0 : st.y0 + k * st.lane - w / 2;
57
+ parts.shapes.push(line_("straight-line", st.x0, y, st.x1, y, w));
58
+ }
59
+ parts.shapes.push(line_("straight-end", st.x0, st.y0, st.x0, edge, w), line_("straight-end", st.x1, st.y0, st.x1, edge, w));
60
+ parts.shapes.push(line_("finish-line", st.finish, st.y0, st.finish, edge, w));
61
+ for (let n = 1; n <= st.lanes; n += 1) {
62
+ const y = st.y0 + (n - 0.5) * st.lane;
63
+ parts.shapes.push(line("finish-tick", "finish-line", st.finish - 1, y - 0.4, st.finish - 1, y + 0.4, { w: 0.03, least: 0.08 }));
64
+ if (numbers)
65
+ parts.digits.push({ id: "finish-number", feature: "lane-numbers", text: String(n), x: st.finish - 2.6, y, h: Math.min(0.6, st.lane * 0.55) });
66
+ }
67
+ return parts;
68
+ }
69
+ const line_ = (id, x0, y0, x1, y1, w) => line(id, "lane-lines", x0, y0, x1, y1, { w });
70
+ /** The surface of the oval and of the straight, the kerb, the lane lines, the finish line and the numbers before it. */
71
+ export function ovalParts(o, fig, straight, numbers, hole) {
72
+ const parts = emptyParts();
73
+ const S = o.straight;
74
+ const R = o.radius;
75
+ const Rout = outerRadius(o);
76
+ const w = o.line;
77
+ // The surface: the ring between the kerb and the outer edge, and the straight's.
78
+ // The surface is one shape: the oval's outer edge less the turf's (or, with none, the kerb's) outline, so that the synthetic surface of the segments joins the oval's with no seam.
79
+ parts.areas.push({ id: "track", feature: "track", cls: "ky-ath-track", d: stadiumD(S, Rout) + (hole ?? stadiumD(S, R)), evenodd: true });
80
+ if (straight !== undefined) {
81
+ const edge = R + straight.lanes * straight.lane;
82
+ parts.areas.push({ id: "straight", feature: "track", cls: "ky-ath-track", d: `M${num(straight.x0)} ${num(R)}H${num(straight.x1)}V${num(edge)}H${num(straight.x0)}Z` });
83
+ }
84
+ // The lane lines: the line on the right of each lane, whose outer edge is at the lane's edge (Rule 14.4), so that a line's middle is half its width inside.
85
+ for (let k = 1; k <= o.lanes; k += 1)
86
+ parts.shapes.push(path(`lane-line-${k}`, "lane-lines", laneLineD(o, laneEdge(o, k) - w / 2, straight), { w }));
87
+ // The kerb, 50 mm wide at the least (Rule 14.1); the rules allow it as wide as 250 mm, and it is drawn a little wider than the lines when the drawing is not at true widths.
88
+ parts.shapes.push(path("kerb", "kerb", stadiumD(S, R - fig.kerb / 2), { w: fig.kerb, least: fig.kerb * 3 }));
89
+ if (straight !== undefined) {
90
+ const sl = straight.lane;
91
+ for (let k = 0; k <= straight.lanes; k += 1) {
92
+ // The inside line of lane 1 is the straight's inside edge; each other line is the outer edge of the lane before it.
93
+ const y = k === 0 ? R : R + k * sl - w / 2;
94
+ if (k <= o.lanes && sl === o.lane) {
95
+ // Between the bends these are the oval's own lines; the straight's run on beyond them.
96
+ parts.shapes.push(line(`straight-line-${k}`, "lane-lines", straight.x0, y, -S / 2, y, { w }), line(`straight-line-${k}`, "lane-lines", S / 2, y, straight.x1, y, { w }));
97
+ }
98
+ else
99
+ parts.shapes.push(line(`straight-line-${k}`, "lane-lines", straight.x0, y, straight.x1, y, { w }));
100
+ }
101
+ // The ends of the straight, across it.
102
+ parts.shapes.push(line("straight-end", "lane-lines", straight.x0, R, straight.x0, R + straight.lanes * sl, { w }), line("straight-end", "lane-lines", straight.x1, R, straight.x1, R + straight.lanes * sl, { w }));
103
+ }
104
+ // The finish line: all lanes, at right angles to the lane lines, on the axis through the centre of the second semicircle (Manual 2.2.1.1).
105
+ const lanesAt = straight === undefined ? o.lanes : straight.lanes;
106
+ const sl = straight === undefined ? o.lane : straight.lane;
107
+ parts.shapes.push(line("finish-line", "finish-line", S / 2, R, S / 2, R + lanesAt * sl, { w }));
108
+ // A white line 0.03 m wide and 0.80 m long may be marked in each lane 1 m before the finish line (Manual 2.2.1.6, "Finish Line").
109
+ for (let n = 1; n <= lanesAt; n += 1) {
110
+ const y = R + (n - 0.5) * sl;
111
+ parts.shapes.push(line("finish-tick", "finish-line", S / 2 - 1, y - 0.4, S / 2 - 1, y + 0.4, { w: 0.03, least: 0.08 }));
112
+ if (numbers)
113
+ parts.digits.push({ id: "finish-number", feature: "lane-numbers", text: String(n), x: S / 2 - 2.6, y, h: Math.min(0.6, sl * 0.55) });
114
+ }
115
+ return parts;
116
+ }
@@ -0,0 +1,97 @@
1
+ import type { Area, Shape } from "../fields.types.ts";
2
+ import { WA_SHORT_TRACK, WA_STANDARD_TRACK, type AthleticsFigures, type AthleticsLeague } from "../leagues/athletics.ts";
3
+ import { type SoccerSpec } from "../surfaces/soccer-spec.ts";
4
+ import type { SurfaceOptions } from "../types.ts";
5
+ import type { Facility } from "./facilities.ts";
6
+ import { type Digits, type StraightPlan } from "./oval.ts";
7
+ import { type RaceMarks } from "./races.ts";
8
+ import { type Oval } from "./track.ts";
9
+ import type { AthleticsFieldEvent, AthleticsInfield, AthleticsRace, AthleticsStyle, AthleticsTrackLook, RaceInfo, WaterJump } from "./types.ts";
10
+ /** A box in metres. */
11
+ export interface MBox {
12
+ x0: number;
13
+ y0: number;
14
+ x1: number;
15
+ y1: number;
16
+ }
17
+ /** A named part of the plan to crop to, in metres: one box, or one at each end (`left` and `right` as the stadium is drawn wide). */
18
+ export type MRange = MBox | {
19
+ left: MBox;
20
+ right: MBox;
21
+ };
22
+ /** A part of the plan to label (`landmarks`): where it is, in metres, and the side of the drawing its label stands on. */
23
+ export interface MMark {
24
+ id: string;
25
+ x: number;
26
+ y: number;
27
+ side: "top" | "bottom";
28
+ }
29
+ /** What an athletics drawing is. */
30
+ export interface AthleticsPlan {
31
+ sport: "athletics";
32
+ league: string;
33
+ /** True for the covered 200 m track. */
34
+ indoor: boolean;
35
+ figures: AthleticsFigures;
36
+ oval: Oval;
37
+ lanes: number;
38
+ straight: StraightPlan | undefined;
39
+ track: AthleticsTrackLook;
40
+ infield: AthleticsInfield;
41
+ /** The playing surface: the outer edge of the oval. The data frame's own box. */
42
+ box: MBox;
43
+ /** Everything drawn: the box and what lies beyond it (the jump strip, the runways' ends, the straight). */
44
+ extent: MBox;
45
+ areas: Area[];
46
+ shapes: Shape[];
47
+ digits: Digits[];
48
+ /** The turf: its outline and the lighter bands, for the mown look. */
49
+ turf: {
50
+ d: string;
51
+ stripes: string;
52
+ } | undefined;
53
+ /** The soccer pitch laid inside the track, and where its corner is. */
54
+ pitch: {
55
+ spec: SoccerSpec;
56
+ x: number;
57
+ y: number;
58
+ } | undefined;
59
+ facilities: Facility[];
60
+ races: RaceMarks[];
61
+ /** The steeplechase's lap, when it is drawn. */
62
+ waterJump: WaterJump | undefined;
63
+ events: AthleticsFieldEvent[];
64
+ /** The width the ordinary line is painted at by the rules, and the width it is drawn at unless `exactLines` says otherwise. */
65
+ lineWidth: number;
66
+ drawnLine: number;
67
+ ranges: Readonly<Record<string, MRange>>;
68
+ marks: MMark[];
69
+ /** The race a close-up of a start (`range: "start"`) shows. */
70
+ start: AthleticsRace;
71
+ /** The close-up of the start of that race, when the options ask for one (`range: "start"`): where it is turned about, and the part shown, in the frame in which the athletes run to the right. */
72
+ startView: {
73
+ pivot: {
74
+ x: number;
75
+ y: number;
76
+ heading: number;
77
+ };
78
+ window: MBox;
79
+ } | undefined;
80
+ /** True when the lane numbers are painted. */
81
+ numbers: boolean;
82
+ /** The field event drawn alone at a large scale, when the options ask for one: its facility is the whole plan. */
83
+ layout?: AthleticsFieldEvent;
84
+ }
85
+ /** The league a set of options asks for: the outdoor standard track, or the covered one. */
86
+ export declare function athleticsLeague(o: Pick<SurfaceOptions, "sport" | "league">): AthleticsLeague;
87
+ /** The field events the options ask for: all of them, none, or a list. @throws Error for a name that is not a field event. */
88
+ export declare function eventsOf(style: AthleticsStyle | undefined): AthleticsFieldEvent[];
89
+ /** The races the options ask to be marked. @throws Error for a name that is not a race. */
90
+ export declare function racesOf(style: AthleticsStyle | undefined, indoor?: boolean): RaceInfo[];
91
+ /** The races the covered track marks: the 60 m and its hurdles on the infield straight, and the races of 200 m to 5000 m on the oval. */
92
+ export declare const INDOOR_RACES: readonly AthleticsRace[];
93
+ /** The number of lanes of the oval the options ask for. */
94
+ export declare function athleticsLanes(o: Pick<SurfaceOptions, "sport" | "league" | "athletics">): number;
95
+ /** The standard track and everything the options ask to be marked on it, as a plan. */
96
+ export declare function athleticsPlan(o: Pick<SurfaceOptions, "sport" | "league" | "athletics" | "units" | "pitch" | "detail"> & Partial<Pick<SurfaceOptions, "range" | "ground">>): AthleticsPlan;
97
+ export { WA_SHORT_TRACK, WA_STANDARD_TRACK };