@willcgage/module-schematic 0.79.0 → 0.81.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/dist/index.cjs +117 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +148 -5
- package/dist/index.d.ts +148 -5
- package/dist/index.js +116 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1454,7 +1454,11 @@ interface TrackPart {
|
|
|
1454
1454
|
/** `flex` is track sold by the length rather than as a fixed geometry — its
|
|
1455
1455
|
* {@link overallLength} is the LONGEST piece you can lay from it, not a shape
|
|
1456
1456
|
* (#193). */
|
|
1457
|
-
|
|
1457
|
+
/** ⚠️ `crossover` is an ASSEMBLY, not a single turnout — two turnouts plus the
|
|
1458
|
+
* diagonal between two parallel tracks, sold as one fixture. It therefore
|
|
1459
|
+
* carries {@link trackSpacing}, which no single turnout has, and its
|
|
1460
|
+
* `frogNumber` describes the two turnouts in it. */
|
|
1461
|
+
kind: "turnout" | "wye" | "curved-turnout" | "crossover" | "crossing" | "flex";
|
|
1458
1462
|
/** Manufacturer part numbers by hand, where the part has a hand. */
|
|
1459
1463
|
partNumbers?: {
|
|
1460
1464
|
left?: string;
|
|
@@ -1484,8 +1488,27 @@ interface TrackPart {
|
|
|
1484
1488
|
* prefer these when both are known: they're what someone can actually put a
|
|
1485
1489
|
* rule against. */
|
|
1486
1490
|
frogOffset?: PartDimension;
|
|
1487
|
-
/** End-to-end length of the part.
|
|
1491
|
+
/** End-to-end length of the part.
|
|
1492
|
+
*
|
|
1493
|
+
* ⚠️ On a {@link buildable} part this is the manufacturer's DEFAULT length,
|
|
1494
|
+
* not a property of the part — the modeller cuts the rail, so their turnout
|
|
1495
|
+
* is whatever they built between {@link minimumLength} and as long as they
|
|
1496
|
+
* like. */
|
|
1488
1497
|
overallLength?: PartDimension;
|
|
1498
|
+
/** True when the product is a FIXTURE or template rather than a finished
|
|
1499
|
+
* turnout — Fast Tracks sell jigs, not parts. The distinction is not cosmetic:
|
|
1500
|
+
* a buildable part has no single length, so `overallLength` becomes a default
|
|
1501
|
+
* and `minimumLength` a floor, and nothing may infer where an owner's actual
|
|
1502
|
+
* turnout ends from either of them. */
|
|
1503
|
+
buildable?: boolean;
|
|
1504
|
+
/** The shortest the part can be built. Buildable parts only. */
|
|
1505
|
+
minimumLength?: PartDimension;
|
|
1506
|
+
/** The radius of plain curve this turnout can stand in for, as a
|
|
1507
|
+
* layout-planning figure. Fast Tracks publish it; Atlas do not. Nothing draws
|
|
1508
|
+
* with it — it is here because it is a real published dimension and dropping
|
|
1509
|
+
* it would mean the library could not represent what a manufacturer actually
|
|
1510
|
+
* says about their own product. */
|
|
1511
|
+
substitutionRadius?: PartDimension;
|
|
1489
1512
|
/** Frog apex → the end of the diverging rail, measured ALONG that rail. The
|
|
1490
1513
|
* independent cross-check on {@link frogOffset}: it must be slightly LONGER
|
|
1491
1514
|
* than the axial `overallLength − frogOffset`, because the rail is the
|
|
@@ -1502,6 +1525,20 @@ interface TrackPart {
|
|
|
1502
1525
|
innerRadius?: PartDimension;
|
|
1503
1526
|
/** Crossing angle, degrees. */
|
|
1504
1527
|
crossingAngleDeg?: number;
|
|
1528
|
+
/** Centre-to-centre distance of the two parallel tracks a {@link kind}
|
|
1529
|
+
* `crossover` joins. A crossover fixture is BUILT for one spacing — it is not
|
|
1530
|
+
* adjustable — so this decides whether the part suits a given standard at all.
|
|
1531
|
+
*
|
|
1532
|
+
* ⚠️ READ {@link FREEMO_TRACK_SPACING_INCHES} ALONGSIDE THIS. Free-moN §2.0
|
|
1533
|
+
* fixes double-track spacing at exactly 1.125″; the Fast Tracks N crossovers
|
|
1534
|
+
* are built to 1.09″. That 0.035″ is small but it is REAL and it is not a
|
|
1535
|
+
* tolerance — the fixture cannot be built to another spacing. Recorded rather
|
|
1536
|
+
* than reconciled: it is a fact about the product, and an owner deciding what
|
|
1537
|
+
* to buy is better served by the true number than by a convenient one. */
|
|
1538
|
+
trackSpacing?: PartDimension;
|
|
1539
|
+
/** The SECOND frog angle on a part that has two — the diamond where the
|
|
1540
|
+
* diagonals of a scissors crossover cross. Published in degrees. */
|
|
1541
|
+
secondaryFrogAngle?: PartAngle;
|
|
1505
1542
|
/** The part's drawn geometry in its own frame, when it came from a library
|
|
1506
1543
|
* file. This is the payload worth importing — real outlines we can draw
|
|
1507
1544
|
* instead of deriving a turnout's shape from a frog number. */
|
|
@@ -1596,6 +1633,93 @@ declare const ATLAS_CODE55_N: TrackPart[];
|
|
|
1596
1633
|
* worse than none — someone would order against it.
|
|
1597
1634
|
*/
|
|
1598
1635
|
declare const FLEX_TRACK_PARTS: TrackPart[];
|
|
1636
|
+
/**
|
|
1637
|
+
* Fast Tracks N-scale assembly fixtures, Micro Engineering Code 55 rail.
|
|
1638
|
+
*
|
|
1639
|
+
* ⚠️ A DIFFERENT MANUFACTURER PUBLISHES DIFFERENT NUMBERS, and the library has
|
|
1640
|
+
* to hold what each one actually says rather than a lowest common denominator.
|
|
1641
|
+
* Fast Tracks publish none of Atlas's three landmarks — no points offset, no
|
|
1642
|
+
* frog offset, no lead — and four things Atlas never state:
|
|
1643
|
+
*
|
|
1644
|
+
* straight angle div R default minimum substitution R
|
|
1645
|
+
* #4 14.04° 8″ 4.57″ 3.43″ 11″
|
|
1646
|
+
* #4.5 12.53° 11″ 5.00″ 3.90″ 14″
|
|
1647
|
+
* #5 11.31° 14″ 5.39″ 3.92″ 17″
|
|
1648
|
+
* #6 9.46° 23″ 6.26″ 4.30″ 24″
|
|
1649
|
+
* #7 8.13° 27″ 7.40″ 5.44″ 34″
|
|
1650
|
+
* #8 7.13° 36″ 8.00″ 5.93″ 42″
|
|
1651
|
+
* #9 6.34° 50″ 8.38″ 6.42″ 57″
|
|
1652
|
+
* #10 5.71° 64″ 9.15″ 6.80″ 70″
|
|
1653
|
+
* #12 4.76° 82″ 10.34″ 7.95″ 90″
|
|
1654
|
+
*
|
|
1655
|
+
* wye angle div R default minimum substitution R
|
|
1656
|
+
* #4 14.04° 23″ 4.63″ 3.48″ 27″
|
|
1657
|
+
* #5 11.31° 25″ 5.23″ 3.81″ 30″
|
|
1658
|
+
* #6 9.46° 35″ 5.99″ 4.30″ 47″
|
|
1659
|
+
* #8 7.13° 70″ 8.22″ 5.93″ 94″
|
|
1660
|
+
* #10 5.71° 89″ 9.47″ 6.97″ 130″
|
|
1661
|
+
*
|
|
1662
|
+
* ⭐ **FAST TRACKS BUILD TO TRUE FROG RATIOS.** Every angle above is `atan(1/N)`
|
|
1663
|
+
* to the digits published — 14.04, 11.31, 9.46, 8.13, 7.13, 6.34, 5.71, 4.76.
|
|
1664
|
+
* Atlas do NOT: they build to SECTIONAL angles (a "#5" is 11.25°, a 1/32 turn,
|
|
1665
|
+
* against theory's 11.310°). Two manufacturers, two different meanings for the
|
|
1666
|
+
* same number on the box, and the difference is real if you ever check whether
|
|
1667
|
+
* a part mates with sectional track.
|
|
1668
|
+
*
|
|
1669
|
+
* ⚠️ THESE ARE FIXTURES, SO THEY HAVE NO LENGTH. The modeller cuts the rail:
|
|
1670
|
+
* `overallLength` here is the manufacturer's DEFAULT and `minimumLength` the
|
|
1671
|
+
* floor. Because Fast Tracks publish no points offset, {@link partExtent}
|
|
1672
|
+
* returns null for every one of them, so none claims a body and flex still runs
|
|
1673
|
+
* through it (#193). That is the honest answer — we do not know where an
|
|
1674
|
+
* owner's hand-built turnout stops, and guessing from a default length would be
|
|
1675
|
+
* inventing a measurement. An owner who measures their own build can enter it,
|
|
1676
|
+
* and the admin form's cross-checks will catch a bad reading.
|
|
1677
|
+
*
|
|
1678
|
+
* Source: handlaidtrack.com product pages, "Detailed Specifications" tables,
|
|
1679
|
+
* read 2026-07-26. ⚠️ The PDF templates in Will's local reference folder are
|
|
1680
|
+
* ENCRYPTED (`/Encrypt /Standard`), so they are deliberately not the source
|
|
1681
|
+
* here — the public product pages say the same thing and can be cited.
|
|
1682
|
+
*/
|
|
1683
|
+
declare const FAST_TRACKS_N_ME55: TrackPart[];
|
|
1684
|
+
/**
|
|
1685
|
+
* Fast Tracks N-scale CROSSOVER fixtures, ME Code 55.
|
|
1686
|
+
*
|
|
1687
|
+
* crossover angle 2nd frog default minimum track spacing
|
|
1688
|
+
* #6 9.46° 19° 10.07″ 9.31″ 1.09″
|
|
1689
|
+
* #8 7.13° 14.3° 13.61″ 13.07″ 1.09″
|
|
1690
|
+
*
|
|
1691
|
+
* ⚠️⚠️ **THE TRACK SPACING IS 1.09″, AND FREE-moN §2.0 REQUIRES 1.125″.**
|
|
1692
|
+
* A crossover fixture is machined for ONE spacing; it is not adjustable. So a
|
|
1693
|
+
* crossover hand-built on either of these puts the parallel track 0.035″ closer
|
|
1694
|
+
* than the standard, and that difference has to go somewhere — the tracks pinch
|
|
1695
|
+
* through the crossover and open back out to meet the endplates, which is fixed
|
|
1696
|
+
* at both ends by {@link FREEMO_TRACK_SPACING_INCHES}.
|
|
1697
|
+
*
|
|
1698
|
+
* Recorded, NOT reconciled. It is 0.9 mm and most builders will absorb it, but
|
|
1699
|
+
* it is a property of the product rather than a tolerance, and someone choosing
|
|
1700
|
+
* what to buy for a double-track Free-moN module is better served by the true
|
|
1701
|
+
* number than a convenient one. Nothing here warns or blocks — that would be a
|
|
1702
|
+
* decision for the app, not for a data table.
|
|
1703
|
+
*
|
|
1704
|
+
* ⭐ THE SECOND FROG IS EXACTLY TWICE THE FIRST — 19° against 2 × 9.46 = 18.92,
|
|
1705
|
+
* and 14.3° against 2 × 7.13 = 14.26, both inside the published rounding. That
|
|
1706
|
+
* is the diamond in a scissors crossover, where two diagonals each leaving at
|
|
1707
|
+
* the frog angle meet each other. It is a free cross-check on the pair, and it
|
|
1708
|
+
* passes.
|
|
1709
|
+
*
|
|
1710
|
+
* ⚠️ A CROSSOVER IS AN ASSEMBLY, so `partExtent` means nothing for it and the
|
|
1711
|
+
* turnout size lookups must never see it: `kind` is `"crossover"`, and every
|
|
1712
|
+
* one of them filters `kind === "turnout"`.
|
|
1713
|
+
*
|
|
1714
|
+
* Atlas make crossover parts too — Will has no figures for them as of
|
|
1715
|
+
* 2026-07-26, so there are deliberately no Atlas entries here rather than
|
|
1716
|
+
* guessed ones.
|
|
1717
|
+
*
|
|
1718
|
+
* Source: handlaidtrack.com product pages, read 2026-07-26. Their tables also
|
|
1719
|
+
* carry tie size and tie spacing; those describe the QuickSticks tie strip's
|
|
1720
|
+
* appearance rather than the track's geometry, so they are not carried here.
|
|
1721
|
+
*/
|
|
1722
|
+
declare const FAST_TRACKS_N_ME55_CROSSOVERS: TrackPart[];
|
|
1599
1723
|
/** What a track is laid with when nobody has said — the commonest N-scale flex. */
|
|
1600
1724
|
declare const DEFAULT_FLEX_PART_ID = "atlas-c55-n-flex";
|
|
1601
1725
|
/** Every built-in part, across manufacturers. */
|
|
@@ -1774,8 +1898,18 @@ declare function partExtent(part: TrackPart | null | undefined): PartExtent | nu
|
|
|
1774
1898
|
* measured part matches EXACTLY. A #6 is not a #5 or a #7 — the nearest part's
|
|
1775
1899
|
* length says nothing about it (see {@link partExtent}). */
|
|
1776
1900
|
declare function partExtentForSize(size: number, library?: TrackPart[]): PartExtent | null;
|
|
1777
|
-
/**
|
|
1778
|
-
*
|
|
1901
|
+
/**
|
|
1902
|
+
* The closest built-in turnout for a frog number — what a bare `size` maps to
|
|
1903
|
+
* when a turnout names no part. Exact match wins; otherwise the nearest frog.
|
|
1904
|
+
*
|
|
1905
|
+
* ⚠️ TIES ARE BROKEN TOWARD A PART WE CAN ACTUALLY DRAW. Two parts can share a
|
|
1906
|
+
* frog number — Atlas sell a #5 and Fast Tracks make a #5 fixture — and only one
|
|
1907
|
+
* of them may carry the measured offsets {@link partExtent} needs. Picking by
|
|
1908
|
+
* frog number alone would let a part with no geometry win on array order and
|
|
1909
|
+
* take the other's body away with it, which is the #193 failure (a turnout that
|
|
1910
|
+
* claims no extent has flex drawn straight through it). So: nearest frog first,
|
|
1911
|
+
* and among equals, one with a real extent.
|
|
1912
|
+
*/
|
|
1779
1913
|
declare function turnoutPartForSize(size: number, library?: TrackPart[]): TrackPart | null;
|
|
1780
1914
|
/**
|
|
1781
1915
|
* The lead to draw a turnout of this size with. Keeps `frogLegOf` honest without
|
|
@@ -1903,6 +2037,15 @@ interface StoredTrackPart {
|
|
|
1903
2037
|
overallLengthSource?: string | null;
|
|
1904
2038
|
divergingLengthInches?: number | null;
|
|
1905
2039
|
divergingLengthSource?: string | null;
|
|
2040
|
+
minimumLengthInches?: number | null;
|
|
2041
|
+
minimumLengthSource?: string | null;
|
|
2042
|
+
substitutionRadiusInches?: number | null;
|
|
2043
|
+
substitutionRadiusSource?: string | null;
|
|
2044
|
+
trackSpacingInches?: number | null;
|
|
2045
|
+
trackSpacingSource?: string | null;
|
|
2046
|
+
secondaryFrogAngleDeg?: number | null;
|
|
2047
|
+
secondaryFrogAngleSource?: string | null;
|
|
2048
|
+
buildable?: boolean | null;
|
|
1906
2049
|
leadInches?: number | null;
|
|
1907
2050
|
leadSource?: string | null;
|
|
1908
2051
|
outerRadiusInches?: number | null;
|
|
@@ -2245,4 +2388,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
2245
2388
|
heading: number;
|
|
2246
2389
|
}>;
|
|
2247
2390
|
|
|
2248
|
-
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
|
|
2391
|
+
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
|
package/dist/index.d.ts
CHANGED
|
@@ -1454,7 +1454,11 @@ interface TrackPart {
|
|
|
1454
1454
|
/** `flex` is track sold by the length rather than as a fixed geometry — its
|
|
1455
1455
|
* {@link overallLength} is the LONGEST piece you can lay from it, not a shape
|
|
1456
1456
|
* (#193). */
|
|
1457
|
-
|
|
1457
|
+
/** ⚠️ `crossover` is an ASSEMBLY, not a single turnout — two turnouts plus the
|
|
1458
|
+
* diagonal between two parallel tracks, sold as one fixture. It therefore
|
|
1459
|
+
* carries {@link trackSpacing}, which no single turnout has, and its
|
|
1460
|
+
* `frogNumber` describes the two turnouts in it. */
|
|
1461
|
+
kind: "turnout" | "wye" | "curved-turnout" | "crossover" | "crossing" | "flex";
|
|
1458
1462
|
/** Manufacturer part numbers by hand, where the part has a hand. */
|
|
1459
1463
|
partNumbers?: {
|
|
1460
1464
|
left?: string;
|
|
@@ -1484,8 +1488,27 @@ interface TrackPart {
|
|
|
1484
1488
|
* prefer these when both are known: they're what someone can actually put a
|
|
1485
1489
|
* rule against. */
|
|
1486
1490
|
frogOffset?: PartDimension;
|
|
1487
|
-
/** End-to-end length of the part.
|
|
1491
|
+
/** End-to-end length of the part.
|
|
1492
|
+
*
|
|
1493
|
+
* ⚠️ On a {@link buildable} part this is the manufacturer's DEFAULT length,
|
|
1494
|
+
* not a property of the part — the modeller cuts the rail, so their turnout
|
|
1495
|
+
* is whatever they built between {@link minimumLength} and as long as they
|
|
1496
|
+
* like. */
|
|
1488
1497
|
overallLength?: PartDimension;
|
|
1498
|
+
/** True when the product is a FIXTURE or template rather than a finished
|
|
1499
|
+
* turnout — Fast Tracks sell jigs, not parts. The distinction is not cosmetic:
|
|
1500
|
+
* a buildable part has no single length, so `overallLength` becomes a default
|
|
1501
|
+
* and `minimumLength` a floor, and nothing may infer where an owner's actual
|
|
1502
|
+
* turnout ends from either of them. */
|
|
1503
|
+
buildable?: boolean;
|
|
1504
|
+
/** The shortest the part can be built. Buildable parts only. */
|
|
1505
|
+
minimumLength?: PartDimension;
|
|
1506
|
+
/** The radius of plain curve this turnout can stand in for, as a
|
|
1507
|
+
* layout-planning figure. Fast Tracks publish it; Atlas do not. Nothing draws
|
|
1508
|
+
* with it — it is here because it is a real published dimension and dropping
|
|
1509
|
+
* it would mean the library could not represent what a manufacturer actually
|
|
1510
|
+
* says about their own product. */
|
|
1511
|
+
substitutionRadius?: PartDimension;
|
|
1489
1512
|
/** Frog apex → the end of the diverging rail, measured ALONG that rail. The
|
|
1490
1513
|
* independent cross-check on {@link frogOffset}: it must be slightly LONGER
|
|
1491
1514
|
* than the axial `overallLength − frogOffset`, because the rail is the
|
|
@@ -1502,6 +1525,20 @@ interface TrackPart {
|
|
|
1502
1525
|
innerRadius?: PartDimension;
|
|
1503
1526
|
/** Crossing angle, degrees. */
|
|
1504
1527
|
crossingAngleDeg?: number;
|
|
1528
|
+
/** Centre-to-centre distance of the two parallel tracks a {@link kind}
|
|
1529
|
+
* `crossover` joins. A crossover fixture is BUILT for one spacing — it is not
|
|
1530
|
+
* adjustable — so this decides whether the part suits a given standard at all.
|
|
1531
|
+
*
|
|
1532
|
+
* ⚠️ READ {@link FREEMO_TRACK_SPACING_INCHES} ALONGSIDE THIS. Free-moN §2.0
|
|
1533
|
+
* fixes double-track spacing at exactly 1.125″; the Fast Tracks N crossovers
|
|
1534
|
+
* are built to 1.09″. That 0.035″ is small but it is REAL and it is not a
|
|
1535
|
+
* tolerance — the fixture cannot be built to another spacing. Recorded rather
|
|
1536
|
+
* than reconciled: it is a fact about the product, and an owner deciding what
|
|
1537
|
+
* to buy is better served by the true number than by a convenient one. */
|
|
1538
|
+
trackSpacing?: PartDimension;
|
|
1539
|
+
/** The SECOND frog angle on a part that has two — the diamond where the
|
|
1540
|
+
* diagonals of a scissors crossover cross. Published in degrees. */
|
|
1541
|
+
secondaryFrogAngle?: PartAngle;
|
|
1505
1542
|
/** The part's drawn geometry in its own frame, when it came from a library
|
|
1506
1543
|
* file. This is the payload worth importing — real outlines we can draw
|
|
1507
1544
|
* instead of deriving a turnout's shape from a frog number. */
|
|
@@ -1596,6 +1633,93 @@ declare const ATLAS_CODE55_N: TrackPart[];
|
|
|
1596
1633
|
* worse than none — someone would order against it.
|
|
1597
1634
|
*/
|
|
1598
1635
|
declare const FLEX_TRACK_PARTS: TrackPart[];
|
|
1636
|
+
/**
|
|
1637
|
+
* Fast Tracks N-scale assembly fixtures, Micro Engineering Code 55 rail.
|
|
1638
|
+
*
|
|
1639
|
+
* ⚠️ A DIFFERENT MANUFACTURER PUBLISHES DIFFERENT NUMBERS, and the library has
|
|
1640
|
+
* to hold what each one actually says rather than a lowest common denominator.
|
|
1641
|
+
* Fast Tracks publish none of Atlas's three landmarks — no points offset, no
|
|
1642
|
+
* frog offset, no lead — and four things Atlas never state:
|
|
1643
|
+
*
|
|
1644
|
+
* straight angle div R default minimum substitution R
|
|
1645
|
+
* #4 14.04° 8″ 4.57″ 3.43″ 11″
|
|
1646
|
+
* #4.5 12.53° 11″ 5.00″ 3.90″ 14″
|
|
1647
|
+
* #5 11.31° 14″ 5.39″ 3.92″ 17″
|
|
1648
|
+
* #6 9.46° 23″ 6.26″ 4.30″ 24″
|
|
1649
|
+
* #7 8.13° 27″ 7.40″ 5.44″ 34″
|
|
1650
|
+
* #8 7.13° 36″ 8.00″ 5.93″ 42″
|
|
1651
|
+
* #9 6.34° 50″ 8.38″ 6.42″ 57″
|
|
1652
|
+
* #10 5.71° 64″ 9.15″ 6.80″ 70″
|
|
1653
|
+
* #12 4.76° 82″ 10.34″ 7.95″ 90″
|
|
1654
|
+
*
|
|
1655
|
+
* wye angle div R default minimum substitution R
|
|
1656
|
+
* #4 14.04° 23″ 4.63″ 3.48″ 27″
|
|
1657
|
+
* #5 11.31° 25″ 5.23″ 3.81″ 30″
|
|
1658
|
+
* #6 9.46° 35″ 5.99″ 4.30″ 47″
|
|
1659
|
+
* #8 7.13° 70″ 8.22″ 5.93″ 94″
|
|
1660
|
+
* #10 5.71° 89″ 9.47″ 6.97″ 130″
|
|
1661
|
+
*
|
|
1662
|
+
* ⭐ **FAST TRACKS BUILD TO TRUE FROG RATIOS.** Every angle above is `atan(1/N)`
|
|
1663
|
+
* to the digits published — 14.04, 11.31, 9.46, 8.13, 7.13, 6.34, 5.71, 4.76.
|
|
1664
|
+
* Atlas do NOT: they build to SECTIONAL angles (a "#5" is 11.25°, a 1/32 turn,
|
|
1665
|
+
* against theory's 11.310°). Two manufacturers, two different meanings for the
|
|
1666
|
+
* same number on the box, and the difference is real if you ever check whether
|
|
1667
|
+
* a part mates with sectional track.
|
|
1668
|
+
*
|
|
1669
|
+
* ⚠️ THESE ARE FIXTURES, SO THEY HAVE NO LENGTH. The modeller cuts the rail:
|
|
1670
|
+
* `overallLength` here is the manufacturer's DEFAULT and `minimumLength` the
|
|
1671
|
+
* floor. Because Fast Tracks publish no points offset, {@link partExtent}
|
|
1672
|
+
* returns null for every one of them, so none claims a body and flex still runs
|
|
1673
|
+
* through it (#193). That is the honest answer — we do not know where an
|
|
1674
|
+
* owner's hand-built turnout stops, and guessing from a default length would be
|
|
1675
|
+
* inventing a measurement. An owner who measures their own build can enter it,
|
|
1676
|
+
* and the admin form's cross-checks will catch a bad reading.
|
|
1677
|
+
*
|
|
1678
|
+
* Source: handlaidtrack.com product pages, "Detailed Specifications" tables,
|
|
1679
|
+
* read 2026-07-26. ⚠️ The PDF templates in Will's local reference folder are
|
|
1680
|
+
* ENCRYPTED (`/Encrypt /Standard`), so they are deliberately not the source
|
|
1681
|
+
* here — the public product pages say the same thing and can be cited.
|
|
1682
|
+
*/
|
|
1683
|
+
declare const FAST_TRACKS_N_ME55: TrackPart[];
|
|
1684
|
+
/**
|
|
1685
|
+
* Fast Tracks N-scale CROSSOVER fixtures, ME Code 55.
|
|
1686
|
+
*
|
|
1687
|
+
* crossover angle 2nd frog default minimum track spacing
|
|
1688
|
+
* #6 9.46° 19° 10.07″ 9.31″ 1.09″
|
|
1689
|
+
* #8 7.13° 14.3° 13.61″ 13.07″ 1.09″
|
|
1690
|
+
*
|
|
1691
|
+
* ⚠️⚠️ **THE TRACK SPACING IS 1.09″, AND FREE-moN §2.0 REQUIRES 1.125″.**
|
|
1692
|
+
* A crossover fixture is machined for ONE spacing; it is not adjustable. So a
|
|
1693
|
+
* crossover hand-built on either of these puts the parallel track 0.035″ closer
|
|
1694
|
+
* than the standard, and that difference has to go somewhere — the tracks pinch
|
|
1695
|
+
* through the crossover and open back out to meet the endplates, which is fixed
|
|
1696
|
+
* at both ends by {@link FREEMO_TRACK_SPACING_INCHES}.
|
|
1697
|
+
*
|
|
1698
|
+
* Recorded, NOT reconciled. It is 0.9 mm and most builders will absorb it, but
|
|
1699
|
+
* it is a property of the product rather than a tolerance, and someone choosing
|
|
1700
|
+
* what to buy for a double-track Free-moN module is better served by the true
|
|
1701
|
+
* number than a convenient one. Nothing here warns or blocks — that would be a
|
|
1702
|
+
* decision for the app, not for a data table.
|
|
1703
|
+
*
|
|
1704
|
+
* ⭐ THE SECOND FROG IS EXACTLY TWICE THE FIRST — 19° against 2 × 9.46 = 18.92,
|
|
1705
|
+
* and 14.3° against 2 × 7.13 = 14.26, both inside the published rounding. That
|
|
1706
|
+
* is the diamond in a scissors crossover, where two diagonals each leaving at
|
|
1707
|
+
* the frog angle meet each other. It is a free cross-check on the pair, and it
|
|
1708
|
+
* passes.
|
|
1709
|
+
*
|
|
1710
|
+
* ⚠️ A CROSSOVER IS AN ASSEMBLY, so `partExtent` means nothing for it and the
|
|
1711
|
+
* turnout size lookups must never see it: `kind` is `"crossover"`, and every
|
|
1712
|
+
* one of them filters `kind === "turnout"`.
|
|
1713
|
+
*
|
|
1714
|
+
* Atlas make crossover parts too — Will has no figures for them as of
|
|
1715
|
+
* 2026-07-26, so there are deliberately no Atlas entries here rather than
|
|
1716
|
+
* guessed ones.
|
|
1717
|
+
*
|
|
1718
|
+
* Source: handlaidtrack.com product pages, read 2026-07-26. Their tables also
|
|
1719
|
+
* carry tie size and tie spacing; those describe the QuickSticks tie strip's
|
|
1720
|
+
* appearance rather than the track's geometry, so they are not carried here.
|
|
1721
|
+
*/
|
|
1722
|
+
declare const FAST_TRACKS_N_ME55_CROSSOVERS: TrackPart[];
|
|
1599
1723
|
/** What a track is laid with when nobody has said — the commonest N-scale flex. */
|
|
1600
1724
|
declare const DEFAULT_FLEX_PART_ID = "atlas-c55-n-flex";
|
|
1601
1725
|
/** Every built-in part, across manufacturers. */
|
|
@@ -1774,8 +1898,18 @@ declare function partExtent(part: TrackPart | null | undefined): PartExtent | nu
|
|
|
1774
1898
|
* measured part matches EXACTLY. A #6 is not a #5 or a #7 — the nearest part's
|
|
1775
1899
|
* length says nothing about it (see {@link partExtent}). */
|
|
1776
1900
|
declare function partExtentForSize(size: number, library?: TrackPart[]): PartExtent | null;
|
|
1777
|
-
/**
|
|
1778
|
-
*
|
|
1901
|
+
/**
|
|
1902
|
+
* The closest built-in turnout for a frog number — what a bare `size` maps to
|
|
1903
|
+
* when a turnout names no part. Exact match wins; otherwise the nearest frog.
|
|
1904
|
+
*
|
|
1905
|
+
* ⚠️ TIES ARE BROKEN TOWARD A PART WE CAN ACTUALLY DRAW. Two parts can share a
|
|
1906
|
+
* frog number — Atlas sell a #5 and Fast Tracks make a #5 fixture — and only one
|
|
1907
|
+
* of them may carry the measured offsets {@link partExtent} needs. Picking by
|
|
1908
|
+
* frog number alone would let a part with no geometry win on array order and
|
|
1909
|
+
* take the other's body away with it, which is the #193 failure (a turnout that
|
|
1910
|
+
* claims no extent has flex drawn straight through it). So: nearest frog first,
|
|
1911
|
+
* and among equals, one with a real extent.
|
|
1912
|
+
*/
|
|
1779
1913
|
declare function turnoutPartForSize(size: number, library?: TrackPart[]): TrackPart | null;
|
|
1780
1914
|
/**
|
|
1781
1915
|
* The lead to draw a turnout of this size with. Keeps `frogLegOf` honest without
|
|
@@ -1903,6 +2037,15 @@ interface StoredTrackPart {
|
|
|
1903
2037
|
overallLengthSource?: string | null;
|
|
1904
2038
|
divergingLengthInches?: number | null;
|
|
1905
2039
|
divergingLengthSource?: string | null;
|
|
2040
|
+
minimumLengthInches?: number | null;
|
|
2041
|
+
minimumLengthSource?: string | null;
|
|
2042
|
+
substitutionRadiusInches?: number | null;
|
|
2043
|
+
substitutionRadiusSource?: string | null;
|
|
2044
|
+
trackSpacingInches?: number | null;
|
|
2045
|
+
trackSpacingSource?: string | null;
|
|
2046
|
+
secondaryFrogAngleDeg?: number | null;
|
|
2047
|
+
secondaryFrogAngleSource?: string | null;
|
|
2048
|
+
buildable?: boolean | null;
|
|
1906
2049
|
leadInches?: number | null;
|
|
1907
2050
|
leadSource?: string | null;
|
|
1908
2051
|
outerRadiusInches?: number | null;
|
|
@@ -2245,4 +2388,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
2245
2388
|
heading: number;
|
|
2246
2389
|
}>;
|
|
2247
2390
|
|
|
2248
|
-
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
|
|
2391
|
+
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
|
package/dist/index.js
CHANGED
|
@@ -1526,8 +1526,97 @@ var FLEX_TRACK_PARTS = [
|
|
|
1526
1526
|
}
|
|
1527
1527
|
}
|
|
1528
1528
|
];
|
|
1529
|
+
var FAST_TRACKS_N_ME55 = [
|
|
1530
|
+
// [kind, N, angle°, divergingR, defaultLength, minLength, substitutionR]
|
|
1531
|
+
["turnout", 4, 14.04, 8, 4.57, 3.43, 11],
|
|
1532
|
+
["turnout", 4.5, 12.53, 11, 5, 3.9, 14],
|
|
1533
|
+
["turnout", 5, 11.31, 14, 5.39, 3.92, 17],
|
|
1534
|
+
["turnout", 6, 9.46, 23, 6.26, 4.3, 24],
|
|
1535
|
+
["turnout", 7, 8.13, 27, 7.4, 5.44, 34],
|
|
1536
|
+
["turnout", 8, 7.13, 36, 8, 5.93, 42],
|
|
1537
|
+
["turnout", 9, 6.34, 50, 8.38, 6.42, 57],
|
|
1538
|
+
["turnout", 10, 5.71, 64, 9.15, 6.8, 70],
|
|
1539
|
+
["turnout", 12, 4.76, 82, 10.34, 7.95, 90],
|
|
1540
|
+
["wye", 4, 14.04, 23, 4.63, 3.48, 27],
|
|
1541
|
+
["wye", 5, 11.31, 25, 5.23, 3.81, 30],
|
|
1542
|
+
["wye", 6, 9.46, 35, 5.99, 4.3, 47],
|
|
1543
|
+
["wye", 8, 7.13, 70, 8.22, 5.93, 94],
|
|
1544
|
+
["wye", 10, 5.71, 89, 9.47, 6.97, 130]
|
|
1545
|
+
].map(([kind, n, deg, divR, dflt, min, subR]) => {
|
|
1546
|
+
const code = kind === "wye" ? "y" : "t";
|
|
1547
|
+
const spec = "handlaidtrack.com Detailed Specifications, read 2026-07-26";
|
|
1548
|
+
const manufacturer = "manufacturer";
|
|
1549
|
+
return {
|
|
1550
|
+
id: `fast-tracks-n-me55-${code}-${n}`,
|
|
1551
|
+
manufacturer: "Fast Tracks",
|
|
1552
|
+
line: "Code 55",
|
|
1553
|
+
scale: "N",
|
|
1554
|
+
// Named for what the OWNER has, not what Fast Tracks sell. They sell a jig;
|
|
1555
|
+
// the person picking this in the editor is holding the turnout they built
|
|
1556
|
+
// on it. `buildable` and the AF-… part number carry the fixture fact.
|
|
1557
|
+
name: `#${n} ${kind === "wye" ? "Wye" : "Turnout"}`,
|
|
1558
|
+
kind,
|
|
1559
|
+
partNumbers: { single: `AF-N-${code.toUpperCase()}-${n}-ME55` },
|
|
1560
|
+
frogNumber: n,
|
|
1561
|
+
buildable: true,
|
|
1562
|
+
actualAngle: {
|
|
1563
|
+
deg,
|
|
1564
|
+
source: manufacturer,
|
|
1565
|
+
note: `${spec}. Matches atan(1/${n}) to the published digits \u2014 Fast Tracks build to TRUE frog ratios, unlike Atlas's sectional angles.`
|
|
1566
|
+
},
|
|
1567
|
+
divergingRadius: { inches: divR, source: manufacturer, note: spec },
|
|
1568
|
+
overallLength: {
|
|
1569
|
+
inches: dflt,
|
|
1570
|
+
source: manufacturer,
|
|
1571
|
+
note: `${spec}. The DEFAULT length \u2014 this is a fixture, so the builder chooses.`
|
|
1572
|
+
},
|
|
1573
|
+
minimumLength: { inches: min, source: manufacturer, note: spec },
|
|
1574
|
+
substitutionRadius: { inches: subR, source: manufacturer, note: spec }
|
|
1575
|
+
};
|
|
1576
|
+
});
|
|
1577
|
+
var FAST_TRACKS_N_ME55_CROSSOVERS = [
|
|
1578
|
+
// [N, angle°, secondFrog°, defaultLength, minLength, trackSpacing]
|
|
1579
|
+
[6, 9.46, 19, 10.07, 9.31, 1.09],
|
|
1580
|
+
[8, 7.13, 14.3, 13.61, 13.07, 1.09]
|
|
1581
|
+
].map(([n, deg, second, dflt, min, spacing]) => {
|
|
1582
|
+
const spec = "handlaidtrack.com Detailed Specifications, read 2026-07-26";
|
|
1583
|
+
const manufacturer = "manufacturer";
|
|
1584
|
+
return {
|
|
1585
|
+
id: `fast-tracks-n-me55-c-${n}`,
|
|
1586
|
+
manufacturer: "Fast Tracks",
|
|
1587
|
+
line: "Code 55",
|
|
1588
|
+
scale: "N",
|
|
1589
|
+
name: `#${n} Crossover`,
|
|
1590
|
+
kind: "crossover",
|
|
1591
|
+
partNumbers: { single: `AF-N-C-${n}-ME55` },
|
|
1592
|
+
frogNumber: n,
|
|
1593
|
+
buildable: true,
|
|
1594
|
+
actualAngle: { deg, source: manufacturer, note: `${spec}. atan(1/${n}) exactly.` },
|
|
1595
|
+
secondaryFrogAngle: {
|
|
1596
|
+
deg: second,
|
|
1597
|
+
source: manufacturer,
|
|
1598
|
+
note: `${spec}. The diamond of a scissors crossover \u2014 2 \xD7 ${deg}\xB0 within the published rounding.`
|
|
1599
|
+
},
|
|
1600
|
+
overallLength: {
|
|
1601
|
+
inches: dflt,
|
|
1602
|
+
source: manufacturer,
|
|
1603
|
+
note: `${spec}. The DEFAULT length of the whole assembly \u2014 a fixture, so the builder chooses.`
|
|
1604
|
+
},
|
|
1605
|
+
minimumLength: { inches: min, source: manufacturer, note: spec },
|
|
1606
|
+
trackSpacing: {
|
|
1607
|
+
inches: spacing,
|
|
1608
|
+
source: manufacturer,
|
|
1609
|
+
note: `${spec}. \u26A0\uFE0F Free-moN \xA72.0 requires ${FREEMO_TRACK_SPACING_INCHES}\u2033 \u2014 this fixture is built to ${spacing}\u2033, ${(FREEMO_TRACK_SPACING_INCHES - spacing).toFixed(3)}\u2033 tighter, and cannot be built to another spacing.`
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
});
|
|
1529
1613
|
var DEFAULT_FLEX_PART_ID = "atlas-c55-n-flex";
|
|
1530
|
-
var BUILT_IN_TRACK_PARTS = [
|
|
1614
|
+
var BUILT_IN_TRACK_PARTS = [
|
|
1615
|
+
...ATLAS_CODE55_N,
|
|
1616
|
+
...FAST_TRACKS_N_ME55,
|
|
1617
|
+
...FAST_TRACKS_N_ME55_CROSSOVERS,
|
|
1618
|
+
...FLEX_TRACK_PARTS
|
|
1619
|
+
];
|
|
1531
1620
|
function flexParts(library = BUILT_IN_TRACK_PARTS) {
|
|
1532
1621
|
return library.filter((p) => p.kind === "flex");
|
|
1533
1622
|
}
|
|
@@ -1654,9 +1743,14 @@ function partExtentForSize(size, library = BUILT_IN_TRACK_PARTS) {
|
|
|
1654
1743
|
function turnoutPartForSize(size, library = BUILT_IN_TRACK_PARTS) {
|
|
1655
1744
|
const turnouts = library.filter((p) => p.kind === "turnout" && p.frogNumber != null);
|
|
1656
1745
|
if (!turnouts.length) return null;
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1746
|
+
const dist = (p) => Math.abs(p.frogNumber - size);
|
|
1747
|
+
return turnouts.reduce((best, p) => {
|
|
1748
|
+
const d = dist(p);
|
|
1749
|
+
const bd = dist(best);
|
|
1750
|
+
if (d !== bd) return d < bd ? p : best;
|
|
1751
|
+
if (!partExtent(best) && partExtent(p)) return p;
|
|
1752
|
+
return best;
|
|
1753
|
+
});
|
|
1660
1754
|
}
|
|
1661
1755
|
function measuredLeadPoints(library) {
|
|
1662
1756
|
return library.filter(
|
|
@@ -1664,8 +1758,10 @@ function measuredLeadPoints(library) {
|
|
|
1664
1758
|
).map((p) => ({ n: p.frogNumber, lead: p.lead.inches })).sort((a, b) => a.n - b.n);
|
|
1665
1759
|
}
|
|
1666
1760
|
function leadInchesForSize(size, library = BUILT_IN_TRACK_PARTS) {
|
|
1667
|
-
const
|
|
1668
|
-
|
|
1761
|
+
const exact = library.find(
|
|
1762
|
+
(p) => p.kind === "turnout" && p.frogNumber === size && p.lead != null
|
|
1763
|
+
);
|
|
1764
|
+
if (exact) return exact.lead.inches;
|
|
1669
1765
|
const pts = measuredLeadPoints(library);
|
|
1670
1766
|
if (!pts.length) return size * TURNOUT_LEAD_INCHES_PER_FROG;
|
|
1671
1767
|
if (pts.length === 1) return size / pts[0].n * pts[0].lead;
|
|
@@ -1842,6 +1938,19 @@ function storedPartToTrackPart(row) {
|
|
|
1842
1938
|
if (overall) part.overallLength = overall;
|
|
1843
1939
|
const diverging = dim(row.divergingLengthInches, row.divergingLengthSource);
|
|
1844
1940
|
if (diverging) part.divergingLength = diverging;
|
|
1941
|
+
const minimum = dim(row.minimumLengthInches, row.minimumLengthSource);
|
|
1942
|
+
if (minimum) part.minimumLength = minimum;
|
|
1943
|
+
const substitution = dim(row.substitutionRadiusInches, row.substitutionRadiusSource);
|
|
1944
|
+
if (substitution) part.substitutionRadius = substitution;
|
|
1945
|
+
const spacing = dim(row.trackSpacingInches, row.trackSpacingSource);
|
|
1946
|
+
if (spacing) part.trackSpacing = spacing;
|
|
1947
|
+
if (typeof row.secondaryFrogAngleDeg === "number")
|
|
1948
|
+
part.secondaryFrogAngle = {
|
|
1949
|
+
deg: row.secondaryFrogAngleDeg,
|
|
1950
|
+
source: asSource(row.secondaryFrogAngleSource),
|
|
1951
|
+
...note ? { note } : {}
|
|
1952
|
+
};
|
|
1953
|
+
if (row.buildable) part.buildable = true;
|
|
1845
1954
|
if (lead) part.lead = lead;
|
|
1846
1955
|
const outer = dim(row.outerRadiusInches, row.radiusSource);
|
|
1847
1956
|
const inner = dim(row.innerRadiusInches, row.radiusSource);
|
|
@@ -2536,6 +2645,6 @@ function poseOverridesFromDoc(doc) {
|
|
|
2536
2645
|
return out;
|
|
2537
2646
|
}
|
|
2538
2647
|
|
|
2539
|
-
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, RAIL_GAUGE_INCHES, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
|
|
2648
|
+
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, RAIL_GAUGE_INCHES, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
|
|
2540
2649
|
//# sourceMappingURL=index.js.map
|
|
2541
2650
|
//# sourceMappingURL=index.js.map
|