@willcgage/module-schematic 0.55.0 → 0.57.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 +106 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -26
- package/dist/index.d.ts +90 -26
- package/dist/index.js +104 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1035,18 +1035,24 @@ interface ModuleFeatures {
|
|
|
1035
1035
|
/** N-scale track gauge, inches (9 mm). */
|
|
1036
1036
|
declare const RAIL_GAUGE_INCHES = 0.354;
|
|
1037
1037
|
/**
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1038
|
+
* ⚠️⚠️ **DEAD — REFUTED *AND* BASELESS. NOTHING SHOULD REACH THIS.** Kept only
|
|
1039
|
+
* so a library with no measured leads at all still returns a number, and as a
|
|
1040
|
+
* record of how the mistake was made.
|
|
1041
1041
|
*
|
|
1042
|
-
* It
|
|
1043
|
-
*
|
|
1042
|
+
* It was points→frog for a #1 frog: a turnout's LEAD if lead were proportional
|
|
1043
|
+
* to frog number, from an Atlas #7 measuring 3⅜″ (Steve Branton, #173) ⇒
|
|
1044
|
+
* 3.375 / 7.
|
|
1044
1045
|
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1046
|
+
* TWO independent things are wrong with it:
|
|
1047
|
+
* 1. **Lead is not proportional to N.** Measured lead ÷ N: #5 = 0.600,
|
|
1048
|
+
* #7 = 0.513, #10 = 0.494. It reads ~20% SHORT at N=5.
|
|
1049
|
+
* 2. **Its founding measurement was superseded.** Will Gage re-measured the same
|
|
1050
|
+
* part at 3¹⁹⁄₃₂″, ⁷⁄₃₂″ longer, confirmed against his own points and frog
|
|
1051
|
+
* positions. So 0.482 is not even the right constant for the wrong model.
|
|
1052
|
+
*
|
|
1053
|
+
* {@link leadInchesForSize} now INTERPOLATES across the measured parts instead.
|
|
1054
|
+
* A single measurement can only ever be scaled — which is this rule — so the
|
|
1055
|
+
* lesson is that one data point cannot support a shape, only a value.
|
|
1050
1056
|
*
|
|
1051
1057
|
* A constant-switch-angle model was also proposed here and is likewise REFUTED:
|
|
1052
1058
|
* inverting {@link turnoutClosure} gives α = 0.036 (#5), 0.067 (#7), 0.043
|
|
@@ -1122,6 +1128,16 @@ interface TrackPart {
|
|
|
1122
1128
|
innerRadius?: PartDimension;
|
|
1123
1129
|
/** Crossing angle, degrees. */
|
|
1124
1130
|
crossingAngleDeg?: number;
|
|
1131
|
+
/** The part's drawn geometry in its own frame, when it came from a library
|
|
1132
|
+
* file. This is the payload worth importing — real outlines we can draw
|
|
1133
|
+
* instead of deriving a turnout's shape from a frog number. */
|
|
1134
|
+
segments?: PartSegment[];
|
|
1135
|
+
/** Connection points, each carrying position AND tangent. The seam a piece
|
|
1136
|
+
* graph would snap on (#179 stage 1-2). */
|
|
1137
|
+
ends?: PartEnd[];
|
|
1138
|
+
/** Set when the part came from an imported library file rather than our own
|
|
1139
|
+
* data — names the source so a user can tell where a dimension came from. */
|
|
1140
|
+
importedFrom?: string;
|
|
1125
1141
|
}
|
|
1126
1142
|
/** N-scale code 55 rail height, inches — Atlas publish .055″. */
|
|
1127
1143
|
declare const CODE55_RAIL_HEIGHT_INCHES = 0.055;
|
|
@@ -1135,18 +1151,23 @@ declare const CODE55_RAIL_HEIGHT_INCHES = 0.055;
|
|
|
1135
1151
|
*
|
|
1136
1152
|
* MEASURED GEOMETRY (all Will Gage's, off physical parts, frog taken at the V):
|
|
1137
1153
|
*
|
|
1138
|
-
* part points frog V overall lead
|
|
1139
|
-
* #5 1¾″ 4.75″ 6.00″ 3.
|
|
1140
|
-
* #7
|
|
1141
|
-
* #10 ⁹⁄₁₆″ 5.50″ 8.00″ 4.
|
|
1154
|
+
* part points frog V overall lead past frog ÷N
|
|
1155
|
+
* #5 1¾″ 4.75″ 6.00″ 3.00000″ 1.25″ 0.2500
|
|
1156
|
+
* #7 ⁵⁄₈″ 4⁷⁄₃₂″ 6.00″ 3.59375″ 1.78125″ 0.2545
|
|
1157
|
+
* #10 ⁹⁄₁₆″ 5.50″ 8.00″ 4.93750″ 2.50″ 0.2500
|
|
1142
1158
|
*
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1159
|
+
* Every one of these is Will Gage's, off a physical part, frog taken at the V.
|
|
1160
|
+
* ⚠️ The #7 lead SUPERSEDES Steve Branton's 3⅜″ (#173) — the library's founding
|
|
1161
|
+
* measurement, ⁷⁄₃₂″ short. Will's single-span reading and his two positions
|
|
1162
|
+
* agree exactly, which is why it wins. Steve's number was also the sole basis of
|
|
1163
|
+
* {@link TURNOUT_LEAD_INCHES_PER_FROG}; that constant is now baseless as well as
|
|
1164
|
+
* refuted, and {@link leadInchesForSize} interpolates across this table instead.
|
|
1146
1165
|
*
|
|
1147
1166
|
* ⭐ **THE PART RUNS PAST THE FROG FAR ENOUGH TO GAIN 0.25″ OF SEPARATION.**
|
|
1148
|
-
* Past-frog run ÷ N is 0.2500 / 0.
|
|
1149
|
-
* within
|
|
1167
|
+
* Past-frog run ÷ N is 0.2500 / 0.2545 / 0.2500 — the #5 and #10 EXACT, the #7
|
|
1168
|
+
* within ¹⁄₃₂″ of the tie end (a 4¼″ frog would make it exact too, one tape
|
|
1169
|
+
* division away). Provenance note: the measurer was told that prediction BEFORE
|
|
1170
|
+
* re-reading and did not return 4¼″, so this is not a confirmation artefact. At the frog
|
|
1150
1171
|
* the routes are one gauge apart; at the end of the moulding they are
|
|
1151
1172
|
* 0.354 + 0.25 ≈ 0.6″ apart. So Atlas size the moulding for a constant
|
|
1152
1173
|
* CLEARANCE, not a constant length — which is what a manufacturer would
|
|
@@ -1158,10 +1179,11 @@ declare const CODE55_RAIL_HEIGHT_INCHES = 0.055;
|
|
|
1158
1179
|
*
|
|
1159
1180
|
* NOTHING HERE IS PROPORTIONAL TO FROG NUMBER. Three rules assumed otherwise;
|
|
1160
1181
|
* all three were tested against a physical part and FAILED:
|
|
1161
|
-
* - ❌ **Lead ∝ N.** Measured lead ÷ N: #5 = 0.600, #7 = 0.
|
|
1162
|
-
* {@link TURNOUT_LEAD_INCHES_PER_FROG} reads ~20% SHORT at N=5
|
|
1182
|
+
* - ❌ **Lead ∝ N.** Measured lead ÷ N: #5 = 0.600, #7 = 0.513, #10 = 0.494.
|
|
1183
|
+
* {@link TURNOUT_LEAD_INCHES_PER_FROG} reads ~20% SHORT at N=5 — and its
|
|
1184
|
+
* founding measurement has since been superseded, so it is baseless too.
|
|
1163
1185
|
* - ❌ **Constant switch angle.** Inverting {@link turnoutClosure} gives α =
|
|
1164
|
-
* 0.036 (#5), 0.
|
|
1186
|
+
* 0.036 (#5), 0.055 (#7), 0.043 (#10). Not constant.
|
|
1165
1187
|
* - ❌ **Overall length ∝ N.** #5 = 6.00″ and #7 = 6.00″ — same moulding, two
|
|
1166
1188
|
* frog numbers.
|
|
1167
1189
|
* - ❌ **Frog fixed at 4.75″** (shipped in 0.54.0, retracted in 0.55.0). It
|
|
@@ -1182,9 +1204,19 @@ declare function trackPart(id: string, library?: TrackPart[]): TrackPart | null;
|
|
|
1182
1204
|
/** The closest built-in turnout for a frog number — what a bare `size` maps to
|
|
1183
1205
|
* when a turnout names no part. Exact match wins; otherwise the nearest frog. */
|
|
1184
1206
|
declare function turnoutPartForSize(size: number, library?: TrackPart[]): TrackPart | null;
|
|
1185
|
-
/**
|
|
1186
|
-
*
|
|
1187
|
-
* needing to know the library exists.
|
|
1207
|
+
/**
|
|
1208
|
+
* The lead to draw a turnout of this size with. Keeps `frogLegOf` honest without
|
|
1209
|
+
* it needing to know the library exists.
|
|
1210
|
+
*
|
|
1211
|
+
* 1. An exact part match wins — a #7's measurement says nothing about a #4.
|
|
1212
|
+
* 2. Otherwise INTERPOLATE piecewise-linearly across the measured parts. This
|
|
1213
|
+
* replaced `size × TURNOUT_LEAD_INCHES_PER_FROG`, which was refuted (its
|
|
1214
|
+
* error changes sign across the measured range) and is now baseless besides,
|
|
1215
|
+
* its founding #7 measurement having been superseded.
|
|
1216
|
+
* 3. ⚠️ Outside the measured range the end segments EXTRAPOLATE. Measured leads
|
|
1217
|
+
* span N = 5…10, so a #4 or #12 is a projection, not a reading, and the #2.5
|
|
1218
|
+
* wye is a long way out. Treat those as placeholders until a part is measured.
|
|
1219
|
+
*/
|
|
1188
1220
|
declare function leadInchesForSize(size: number, library?: TrackPart[]): number;
|
|
1189
1221
|
/** One drawn piece of a part's geometry, in the part's own local frame. */
|
|
1190
1222
|
type PartSegment = {
|
|
@@ -1235,6 +1267,38 @@ declare function parseXtpLibrary(text: string): ImportedPart[];
|
|
|
1235
1267
|
* XTrkCAD angles run CLOCKWISE FROM NORTH, so a point on a curve is
|
|
1236
1268
|
* `(cx + r·sin a, cy + r·cos a)`, not the usual cos/sin. */
|
|
1237
1269
|
declare function samplePartSegments(segments: PartSegment[], stepsPerCurve?: number): BenchworkPoint[][];
|
|
1270
|
+
/** Pull a frog number out of a part name — "#5", "No. 5", "Number 7 Left".
|
|
1271
|
+
* Identification, not measurement: it reads the label the maker printed. */
|
|
1272
|
+
declare function frogNumberFromName(name: string | undefined): number | undefined;
|
|
1273
|
+
/**
|
|
1274
|
+
* Convert a parsed `.xtp` part into a library {@link TrackPart}.
|
|
1275
|
+
*
|
|
1276
|
+
* ⚠️⚠️ **DELIBERATELY DERIVES NO `lead` AND NO `frogOffset`.** The shipped Atlas
|
|
1277
|
+
* file's frog positions are internally inconsistent — it puts the #5's frog
|
|
1278
|
+
* FURTHER OUT than the #7's, which cannot be true of physical parts. Every lead
|
|
1279
|
+
* in this library is a physical measurement and must stay that way; an imported
|
|
1280
|
+
* lead would silently outrank {@link leadInchesForSize}'s interpolation across
|
|
1281
|
+
* those measurements, which is exactly the wrong trade.
|
|
1282
|
+
*
|
|
1283
|
+
* What IS taken: identity (manufacturer, name, part number, frog number), the
|
|
1284
|
+
* drawn `segments` and `ends`, and two dimensions the geometry states directly —
|
|
1285
|
+
* overall length along the through axis, and the actual divergence angle. Both
|
|
1286
|
+
* land as `unverified`, because a community CAD file is not a measurement.
|
|
1287
|
+
*/
|
|
1288
|
+
declare function importedPartToTrackPart(part: ImportedPart, sourceName?: string): TrackPart;
|
|
1289
|
+
/**
|
|
1290
|
+
* Fold imported parts into a library.
|
|
1291
|
+
*
|
|
1292
|
+
* **Imports never overwrite. Ever.** They may only fill a gap — attach geometry
|
|
1293
|
+
* a built-in lacks, or add a part we have no entry for. A dimension already
|
|
1294
|
+
* present wins regardless of its source, because our worst built-in value is at
|
|
1295
|
+
* least one we can trace, and this library has already been burned once by a
|
|
1296
|
+
* plausible number from a CAD file (the constant-switch-angle model was fitted
|
|
1297
|
+
* to an `.xtp` figure that turned out to be measured to the wrong landmark).
|
|
1298
|
+
*
|
|
1299
|
+
* Matching is by manufacturer part number first, then manufacturer + frog number.
|
|
1300
|
+
*/
|
|
1301
|
+
declare function mergeImportedParts(imported: ImportedPart[], library?: TrackPart[], sourceName?: string): TrackPart[];
|
|
1238
1302
|
/** A turnout's CLOSURE — the diverging route's lateral offset from the through
|
|
1239
1303
|
* route, from the points (s = 0) to the frog (s = lead) and beyond.
|
|
1240
1304
|
*
|
|
@@ -1428,4 +1492,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
1428
1492
|
heading: number;
|
|
1429
1493
|
}>;
|
|
1430
1494
|
|
|
1431
|
-
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CODE55_RAIL_HEIGHT_INCHES, 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, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, 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 OutlineFace, type PartAngle, type PartDimension, type PartEnd, 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 SectionFootprint, type SectionRelativePos, type SignalFacing, type SignalSide, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateLead, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, poseNeedsManual, poseOverridesFromDoc, remapPos, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutPartForSize };
|
|
1495
|
+
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CODE55_RAIL_HEIGHT_INCHES, 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, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, 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 OutlineFace, type PartAngle, type PartDimension, type PartEnd, 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 SectionFootprint, type SectionRelativePos, type SignalFacing, type SignalSide, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateLead, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, mergeImportedParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, poseNeedsManual, poseOverridesFromDoc, remapPos, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutPartForSize };
|
package/dist/index.d.ts
CHANGED
|
@@ -1035,18 +1035,24 @@ interface ModuleFeatures {
|
|
|
1035
1035
|
/** N-scale track gauge, inches (9 mm). */
|
|
1036
1036
|
declare const RAIL_GAUGE_INCHES = 0.354;
|
|
1037
1037
|
/**
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1038
|
+
* ⚠️⚠️ **DEAD — REFUTED *AND* BASELESS. NOTHING SHOULD REACH THIS.** Kept only
|
|
1039
|
+
* so a library with no measured leads at all still returns a number, and as a
|
|
1040
|
+
* record of how the mistake was made.
|
|
1041
1041
|
*
|
|
1042
|
-
* It
|
|
1043
|
-
*
|
|
1042
|
+
* It was points→frog for a #1 frog: a turnout's LEAD if lead were proportional
|
|
1043
|
+
* to frog number, from an Atlas #7 measuring 3⅜″ (Steve Branton, #173) ⇒
|
|
1044
|
+
* 3.375 / 7.
|
|
1044
1045
|
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1046
|
+
* TWO independent things are wrong with it:
|
|
1047
|
+
* 1. **Lead is not proportional to N.** Measured lead ÷ N: #5 = 0.600,
|
|
1048
|
+
* #7 = 0.513, #10 = 0.494. It reads ~20% SHORT at N=5.
|
|
1049
|
+
* 2. **Its founding measurement was superseded.** Will Gage re-measured the same
|
|
1050
|
+
* part at 3¹⁹⁄₃₂″, ⁷⁄₃₂″ longer, confirmed against his own points and frog
|
|
1051
|
+
* positions. So 0.482 is not even the right constant for the wrong model.
|
|
1052
|
+
*
|
|
1053
|
+
* {@link leadInchesForSize} now INTERPOLATES across the measured parts instead.
|
|
1054
|
+
* A single measurement can only ever be scaled — which is this rule — so the
|
|
1055
|
+
* lesson is that one data point cannot support a shape, only a value.
|
|
1050
1056
|
*
|
|
1051
1057
|
* A constant-switch-angle model was also proposed here and is likewise REFUTED:
|
|
1052
1058
|
* inverting {@link turnoutClosure} gives α = 0.036 (#5), 0.067 (#7), 0.043
|
|
@@ -1122,6 +1128,16 @@ interface TrackPart {
|
|
|
1122
1128
|
innerRadius?: PartDimension;
|
|
1123
1129
|
/** Crossing angle, degrees. */
|
|
1124
1130
|
crossingAngleDeg?: number;
|
|
1131
|
+
/** The part's drawn geometry in its own frame, when it came from a library
|
|
1132
|
+
* file. This is the payload worth importing — real outlines we can draw
|
|
1133
|
+
* instead of deriving a turnout's shape from a frog number. */
|
|
1134
|
+
segments?: PartSegment[];
|
|
1135
|
+
/** Connection points, each carrying position AND tangent. The seam a piece
|
|
1136
|
+
* graph would snap on (#179 stage 1-2). */
|
|
1137
|
+
ends?: PartEnd[];
|
|
1138
|
+
/** Set when the part came from an imported library file rather than our own
|
|
1139
|
+
* data — names the source so a user can tell where a dimension came from. */
|
|
1140
|
+
importedFrom?: string;
|
|
1125
1141
|
}
|
|
1126
1142
|
/** N-scale code 55 rail height, inches — Atlas publish .055″. */
|
|
1127
1143
|
declare const CODE55_RAIL_HEIGHT_INCHES = 0.055;
|
|
@@ -1135,18 +1151,23 @@ declare const CODE55_RAIL_HEIGHT_INCHES = 0.055;
|
|
|
1135
1151
|
*
|
|
1136
1152
|
* MEASURED GEOMETRY (all Will Gage's, off physical parts, frog taken at the V):
|
|
1137
1153
|
*
|
|
1138
|
-
* part points frog V overall lead
|
|
1139
|
-
* #5 1¾″ 4.75″ 6.00″ 3.
|
|
1140
|
-
* #7
|
|
1141
|
-
* #10 ⁹⁄₁₆″ 5.50″ 8.00″ 4.
|
|
1154
|
+
* part points frog V overall lead past frog ÷N
|
|
1155
|
+
* #5 1¾″ 4.75″ 6.00″ 3.00000″ 1.25″ 0.2500
|
|
1156
|
+
* #7 ⁵⁄₈″ 4⁷⁄₃₂″ 6.00″ 3.59375″ 1.78125″ 0.2545
|
|
1157
|
+
* #10 ⁹⁄₁₆″ 5.50″ 8.00″ 4.93750″ 2.50″ 0.2500
|
|
1142
1158
|
*
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1159
|
+
* Every one of these is Will Gage's, off a physical part, frog taken at the V.
|
|
1160
|
+
* ⚠️ The #7 lead SUPERSEDES Steve Branton's 3⅜″ (#173) — the library's founding
|
|
1161
|
+
* measurement, ⁷⁄₃₂″ short. Will's single-span reading and his two positions
|
|
1162
|
+
* agree exactly, which is why it wins. Steve's number was also the sole basis of
|
|
1163
|
+
* {@link TURNOUT_LEAD_INCHES_PER_FROG}; that constant is now baseless as well as
|
|
1164
|
+
* refuted, and {@link leadInchesForSize} interpolates across this table instead.
|
|
1146
1165
|
*
|
|
1147
1166
|
* ⭐ **THE PART RUNS PAST THE FROG FAR ENOUGH TO GAIN 0.25″ OF SEPARATION.**
|
|
1148
|
-
* Past-frog run ÷ N is 0.2500 / 0.
|
|
1149
|
-
* within
|
|
1167
|
+
* Past-frog run ÷ N is 0.2500 / 0.2545 / 0.2500 — the #5 and #10 EXACT, the #7
|
|
1168
|
+
* within ¹⁄₃₂″ of the tie end (a 4¼″ frog would make it exact too, one tape
|
|
1169
|
+
* division away). Provenance note: the measurer was told that prediction BEFORE
|
|
1170
|
+
* re-reading and did not return 4¼″, so this is not a confirmation artefact. At the frog
|
|
1150
1171
|
* the routes are one gauge apart; at the end of the moulding they are
|
|
1151
1172
|
* 0.354 + 0.25 ≈ 0.6″ apart. So Atlas size the moulding for a constant
|
|
1152
1173
|
* CLEARANCE, not a constant length — which is what a manufacturer would
|
|
@@ -1158,10 +1179,11 @@ declare const CODE55_RAIL_HEIGHT_INCHES = 0.055;
|
|
|
1158
1179
|
*
|
|
1159
1180
|
* NOTHING HERE IS PROPORTIONAL TO FROG NUMBER. Three rules assumed otherwise;
|
|
1160
1181
|
* all three were tested against a physical part and FAILED:
|
|
1161
|
-
* - ❌ **Lead ∝ N.** Measured lead ÷ N: #5 = 0.600, #7 = 0.
|
|
1162
|
-
* {@link TURNOUT_LEAD_INCHES_PER_FROG} reads ~20% SHORT at N=5
|
|
1182
|
+
* - ❌ **Lead ∝ N.** Measured lead ÷ N: #5 = 0.600, #7 = 0.513, #10 = 0.494.
|
|
1183
|
+
* {@link TURNOUT_LEAD_INCHES_PER_FROG} reads ~20% SHORT at N=5 — and its
|
|
1184
|
+
* founding measurement has since been superseded, so it is baseless too.
|
|
1163
1185
|
* - ❌ **Constant switch angle.** Inverting {@link turnoutClosure} gives α =
|
|
1164
|
-
* 0.036 (#5), 0.
|
|
1186
|
+
* 0.036 (#5), 0.055 (#7), 0.043 (#10). Not constant.
|
|
1165
1187
|
* - ❌ **Overall length ∝ N.** #5 = 6.00″ and #7 = 6.00″ — same moulding, two
|
|
1166
1188
|
* frog numbers.
|
|
1167
1189
|
* - ❌ **Frog fixed at 4.75″** (shipped in 0.54.0, retracted in 0.55.0). It
|
|
@@ -1182,9 +1204,19 @@ declare function trackPart(id: string, library?: TrackPart[]): TrackPart | null;
|
|
|
1182
1204
|
/** The closest built-in turnout for a frog number — what a bare `size` maps to
|
|
1183
1205
|
* when a turnout names no part. Exact match wins; otherwise the nearest frog. */
|
|
1184
1206
|
declare function turnoutPartForSize(size: number, library?: TrackPart[]): TrackPart | null;
|
|
1185
|
-
/**
|
|
1186
|
-
*
|
|
1187
|
-
* needing to know the library exists.
|
|
1207
|
+
/**
|
|
1208
|
+
* The lead to draw a turnout of this size with. Keeps `frogLegOf` honest without
|
|
1209
|
+
* it needing to know the library exists.
|
|
1210
|
+
*
|
|
1211
|
+
* 1. An exact part match wins — a #7's measurement says nothing about a #4.
|
|
1212
|
+
* 2. Otherwise INTERPOLATE piecewise-linearly across the measured parts. This
|
|
1213
|
+
* replaced `size × TURNOUT_LEAD_INCHES_PER_FROG`, which was refuted (its
|
|
1214
|
+
* error changes sign across the measured range) and is now baseless besides,
|
|
1215
|
+
* its founding #7 measurement having been superseded.
|
|
1216
|
+
* 3. ⚠️ Outside the measured range the end segments EXTRAPOLATE. Measured leads
|
|
1217
|
+
* span N = 5…10, so a #4 or #12 is a projection, not a reading, and the #2.5
|
|
1218
|
+
* wye is a long way out. Treat those as placeholders until a part is measured.
|
|
1219
|
+
*/
|
|
1188
1220
|
declare function leadInchesForSize(size: number, library?: TrackPart[]): number;
|
|
1189
1221
|
/** One drawn piece of a part's geometry, in the part's own local frame. */
|
|
1190
1222
|
type PartSegment = {
|
|
@@ -1235,6 +1267,38 @@ declare function parseXtpLibrary(text: string): ImportedPart[];
|
|
|
1235
1267
|
* XTrkCAD angles run CLOCKWISE FROM NORTH, so a point on a curve is
|
|
1236
1268
|
* `(cx + r·sin a, cy + r·cos a)`, not the usual cos/sin. */
|
|
1237
1269
|
declare function samplePartSegments(segments: PartSegment[], stepsPerCurve?: number): BenchworkPoint[][];
|
|
1270
|
+
/** Pull a frog number out of a part name — "#5", "No. 5", "Number 7 Left".
|
|
1271
|
+
* Identification, not measurement: it reads the label the maker printed. */
|
|
1272
|
+
declare function frogNumberFromName(name: string | undefined): number | undefined;
|
|
1273
|
+
/**
|
|
1274
|
+
* Convert a parsed `.xtp` part into a library {@link TrackPart}.
|
|
1275
|
+
*
|
|
1276
|
+
* ⚠️⚠️ **DELIBERATELY DERIVES NO `lead` AND NO `frogOffset`.** The shipped Atlas
|
|
1277
|
+
* file's frog positions are internally inconsistent — it puts the #5's frog
|
|
1278
|
+
* FURTHER OUT than the #7's, which cannot be true of physical parts. Every lead
|
|
1279
|
+
* in this library is a physical measurement and must stay that way; an imported
|
|
1280
|
+
* lead would silently outrank {@link leadInchesForSize}'s interpolation across
|
|
1281
|
+
* those measurements, which is exactly the wrong trade.
|
|
1282
|
+
*
|
|
1283
|
+
* What IS taken: identity (manufacturer, name, part number, frog number), the
|
|
1284
|
+
* drawn `segments` and `ends`, and two dimensions the geometry states directly —
|
|
1285
|
+
* overall length along the through axis, and the actual divergence angle. Both
|
|
1286
|
+
* land as `unverified`, because a community CAD file is not a measurement.
|
|
1287
|
+
*/
|
|
1288
|
+
declare function importedPartToTrackPart(part: ImportedPart, sourceName?: string): TrackPart;
|
|
1289
|
+
/**
|
|
1290
|
+
* Fold imported parts into a library.
|
|
1291
|
+
*
|
|
1292
|
+
* **Imports never overwrite. Ever.** They may only fill a gap — attach geometry
|
|
1293
|
+
* a built-in lacks, or add a part we have no entry for. A dimension already
|
|
1294
|
+
* present wins regardless of its source, because our worst built-in value is at
|
|
1295
|
+
* least one we can trace, and this library has already been burned once by a
|
|
1296
|
+
* plausible number from a CAD file (the constant-switch-angle model was fitted
|
|
1297
|
+
* to an `.xtp` figure that turned out to be measured to the wrong landmark).
|
|
1298
|
+
*
|
|
1299
|
+
* Matching is by manufacturer part number first, then manufacturer + frog number.
|
|
1300
|
+
*/
|
|
1301
|
+
declare function mergeImportedParts(imported: ImportedPart[], library?: TrackPart[], sourceName?: string): TrackPart[];
|
|
1238
1302
|
/** A turnout's CLOSURE — the diverging route's lateral offset from the through
|
|
1239
1303
|
* route, from the points (s = 0) to the frog (s = lead) and beyond.
|
|
1240
1304
|
*
|
|
@@ -1428,4 +1492,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
1428
1492
|
heading: number;
|
|
1429
1493
|
}>;
|
|
1430
1494
|
|
|
1431
|
-
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CODE55_RAIL_HEIGHT_INCHES, 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, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, 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 OutlineFace, type PartAngle, type PartDimension, type PartEnd, 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 SectionFootprint, type SectionRelativePos, type SignalFacing, type SignalSide, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateLead, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, poseNeedsManual, poseOverridesFromDoc, remapPos, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutPartForSize };
|
|
1495
|
+
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CODE55_RAIL_HEIGHT_INCHES, 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, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, 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 OutlineFace, type PartAngle, type PartDimension, type PartEnd, 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 SectionFootprint, type SectionRelativePos, type SignalFacing, type SignalSide, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateLead, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, mergeImportedParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, poseNeedsManual, poseOverridesFromDoc, remapPos, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutPartForSize };
|
package/dist/index.js
CHANGED
|
@@ -1137,14 +1137,19 @@ var ATLAS_CODE55_N = [
|
|
|
1137
1137
|
partNumbers: { left: "2052", right: "2053" },
|
|
1138
1138
|
frogNumber: 7,
|
|
1139
1139
|
lead: {
|
|
1140
|
-
inches: 3.
|
|
1140
|
+
inches: 3.59375,
|
|
1141
1141
|
source: "measured",
|
|
1142
|
-
note: "
|
|
1142
|
+
note: "Will Gage, physical Atlas 2052 (#7), 3\xB9\u2079\u2044\u2083\u2082\u2033 points\u2192frog as a single span \u2014 and it matches his two positions exactly (4\u2077\u2044\u2083\u2082 \u2212 \u2075\u2044\u2088), so the reading is internally consistent. SUPERSEDES Steve Branton's 3\u215C\u2033 (#173), which was \u2077\u2044\u2083\u2082\u2033 short and was the library's founding measurement. \u26A0\uFE0F Steve's number was also the SOLE basis of TURNOUT_LEAD_INCHES_PER_FROG (3.375/7 = 0.482) \u2014 that constant is now baseless as well as refuted."
|
|
1143
|
+
},
|
|
1144
|
+
pointsOffset: {
|
|
1145
|
+
inches: 0.625,
|
|
1146
|
+
source: "measured",
|
|
1147
|
+
note: "Will Gage, physical Atlas 2052 (#7) \u2014 \xB9\u2070\u2044\u2081\u2086\u2033 tie end to point tips"
|
|
1143
1148
|
},
|
|
1144
1149
|
frogOffset: {
|
|
1145
|
-
inches: 4.
|
|
1150
|
+
inches: 4.21875,
|
|
1146
1151
|
source: "measured",
|
|
1147
|
-
note: "Will Gage, physical Atlas 2052 (#7) \u2014 tie end to the apex of the V"
|
|
1152
|
+
note: "Will Gage, physical Atlas 2052 (#7) \u2014 4\u2077\u2044\u2083\u2082\u2033, tie end to the apex of the V. Supersedes an initial 4\xB3\u2044\u2081\u2086\u2033. Worth noting for provenance: he was told beforehand that the clearance hypothesis predicted 4\xBC\u2033 and did NOT read 4\xBC\u2033 \u2014 so this number is not a confirmation artefact, and it sits \xB9\u2044\u2083\u2082\u2033 (one tape division) from the predicted value."
|
|
1148
1153
|
},
|
|
1149
1154
|
overallLength: {
|
|
1150
1155
|
inches: 6,
|
|
@@ -1230,10 +1235,24 @@ function turnoutPartForSize(size, library = BUILT_IN_TRACK_PARTS) {
|
|
|
1230
1235
|
(best, p) => Math.abs(p.frogNumber - size) < Math.abs(best.frogNumber - size) ? p : best
|
|
1231
1236
|
);
|
|
1232
1237
|
}
|
|
1238
|
+
function measuredLeadPoints(library) {
|
|
1239
|
+
return library.filter(
|
|
1240
|
+
(p) => p.kind === "turnout" && p.frogNumber != null && p.lead?.source === "measured"
|
|
1241
|
+
).map((p) => ({ n: p.frogNumber, lead: p.lead.inches })).sort((a, b) => a.n - b.n);
|
|
1242
|
+
}
|
|
1233
1243
|
function leadInchesForSize(size, library = BUILT_IN_TRACK_PARTS) {
|
|
1234
1244
|
const part = turnoutPartForSize(size, library);
|
|
1235
1245
|
if (part?.lead && part.frogNumber === size) return part.lead.inches;
|
|
1236
|
-
|
|
1246
|
+
const pts = measuredLeadPoints(library);
|
|
1247
|
+
if (!pts.length) return size * TURNOUT_LEAD_INCHES_PER_FROG;
|
|
1248
|
+
if (pts.length === 1) return size / pts[0].n * pts[0].lead;
|
|
1249
|
+
let i;
|
|
1250
|
+
if (size >= pts[pts.length - 1].n) i = pts.length - 2;
|
|
1251
|
+
else i = Math.max(0, pts.findIndex((p) => p.n >= size) - 1);
|
|
1252
|
+
const lo = pts[i];
|
|
1253
|
+
const hi = pts[i + 1];
|
|
1254
|
+
const t = (size - lo.n) / (hi.n - lo.n);
|
|
1255
|
+
return lo.lead + t * (hi.lead - lo.lead);
|
|
1237
1256
|
}
|
|
1238
1257
|
function parseXtpLibrary(text) {
|
|
1239
1258
|
const parts = [];
|
|
@@ -1299,6 +1318,85 @@ function samplePartSegments(segments, stepsPerCurve = 16) {
|
|
|
1299
1318
|
return out;
|
|
1300
1319
|
});
|
|
1301
1320
|
}
|
|
1321
|
+
function angleDeltaDeg(a, b) {
|
|
1322
|
+
let d = ((a - b) % 360 + 540) % 360 - 180;
|
|
1323
|
+
if (d === -180) d = 180;
|
|
1324
|
+
return d;
|
|
1325
|
+
}
|
|
1326
|
+
function frogNumberFromName(name) {
|
|
1327
|
+
if (!name) return void 0;
|
|
1328
|
+
const m = name.match(/(?:#|no\.?\s*|number\s+)(\d+(?:\.\d+)?)/i);
|
|
1329
|
+
if (!m) return void 0;
|
|
1330
|
+
const n = Number(m[1]);
|
|
1331
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
1332
|
+
}
|
|
1333
|
+
function importedKind(name) {
|
|
1334
|
+
const s = (name ?? "").toLowerCase();
|
|
1335
|
+
if (s.includes("wye")) return "wye";
|
|
1336
|
+
if (s.includes("crossing")) return "crossing";
|
|
1337
|
+
if (s.includes("curved")) return "curved-turnout";
|
|
1338
|
+
return "turnout";
|
|
1339
|
+
}
|
|
1340
|
+
var slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1341
|
+
function importedPartToTrackPart(part, sourceName = "imported .xtp") {
|
|
1342
|
+
const name = part.name ?? part.title ?? "Imported part";
|
|
1343
|
+
const manufacturer = part.manufacturer ?? "Unknown";
|
|
1344
|
+
const note = `from ${sourceName} \u2014 community CAD data, not a measurement`;
|
|
1345
|
+
const out = {
|
|
1346
|
+
id: `xtp-${slug(manufacturer)}-${slug(part.partNumber || name)}`,
|
|
1347
|
+
manufacturer,
|
|
1348
|
+
name,
|
|
1349
|
+
line: "",
|
|
1350
|
+
scale: "N",
|
|
1351
|
+
kind: importedKind(name),
|
|
1352
|
+
frogNumber: frogNumberFromName(name),
|
|
1353
|
+
segments: part.segments,
|
|
1354
|
+
ends: part.ends,
|
|
1355
|
+
importedFrom: sourceName
|
|
1356
|
+
};
|
|
1357
|
+
if (part.partNumber) out.partNumbers = { single: part.partNumber };
|
|
1358
|
+
const ends = part.ends;
|
|
1359
|
+
if (ends.length >= 2) {
|
|
1360
|
+
const a = ends[0].angleDeg * Math.PI / 180;
|
|
1361
|
+
const ux = Math.sin(a);
|
|
1362
|
+
const uy = Math.cos(a);
|
|
1363
|
+
const proj = ends.map((e) => (e.x - ends[0].x) * ux + (e.y - ends[0].y) * uy);
|
|
1364
|
+
const span = Math.max(...proj) - Math.min(...proj);
|
|
1365
|
+
if (span > 0) out.overallLength = { inches: span, source: "unverified", note };
|
|
1366
|
+
}
|
|
1367
|
+
if (ends.length >= 3) {
|
|
1368
|
+
const rest = ends.slice(1);
|
|
1369
|
+
const opposite = rest.map((e) => ({ e, off: Math.abs(angleDeltaDeg(e.angleDeg, ends[0].angleDeg + 180)) })).sort((p, q) => p.off - q.off);
|
|
1370
|
+
const through = opposite[0].e;
|
|
1371
|
+
const diverging = opposite[opposite.length - 1].e;
|
|
1372
|
+
const deg = Math.abs(angleDeltaDeg(diverging.angleDeg, through.angleDeg));
|
|
1373
|
+
if (deg > 0.01) out.actualAngle = { deg, source: "unverified", note };
|
|
1374
|
+
}
|
|
1375
|
+
return out;
|
|
1376
|
+
}
|
|
1377
|
+
function mergeImportedParts(imported, library = BUILT_IN_TRACK_PARTS, sourceName = "imported .xtp") {
|
|
1378
|
+
const out = library.map((p) => ({ ...p }));
|
|
1379
|
+
const numbersOf = (p) => [p.partNumbers?.left, p.partNumbers?.right, p.partNumbers?.single].filter(Boolean).map((s) => s.trim().toLowerCase());
|
|
1380
|
+
for (const raw of imported) {
|
|
1381
|
+
const conv = importedPartToTrackPart(raw, sourceName);
|
|
1382
|
+
const pn = raw.partNumber?.trim().toLowerCase();
|
|
1383
|
+
const match = (pn ? out.find((p) => numbersOf(p).includes(pn)) : void 0) ?? (conv.frogNumber != null ? out.find(
|
|
1384
|
+
(p) => p.frogNumber === conv.frogNumber && p.kind === conv.kind && p.manufacturer.toLowerCase() === conv.manufacturer.toLowerCase()
|
|
1385
|
+
) : void 0);
|
|
1386
|
+
if (!match) {
|
|
1387
|
+
out.push(conv);
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
if (!match.segments?.length && conv.segments?.length) match.segments = conv.segments;
|
|
1391
|
+
if (!match.ends?.length && conv.ends?.length) match.ends = conv.ends;
|
|
1392
|
+
if (!match.importedFrom && (conv.segments?.length || conv.ends?.length)) {
|
|
1393
|
+
match.importedFrom = sourceName;
|
|
1394
|
+
}
|
|
1395
|
+
if (!match.overallLength && conv.overallLength) match.overallLength = conv.overallLength;
|
|
1396
|
+
if (!match.actualAngle && conv.actualAngle) match.actualAngle = conv.actualAngle;
|
|
1397
|
+
}
|
|
1398
|
+
return out;
|
|
1399
|
+
}
|
|
1302
1400
|
function turnoutClosure(size, opts = {}) {
|
|
1303
1401
|
const N = size > 0 ? size : 6;
|
|
1304
1402
|
const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
|
|
@@ -1828,6 +1926,6 @@ function poseOverridesFromDoc(doc) {
|
|
|
1828
1926
|
return out;
|
|
1829
1927
|
}
|
|
1830
1928
|
|
|
1831
|
-
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CODE55_RAIL_HEIGHT_INCHES, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, 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, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateLead, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, poseNeedsManual, poseOverridesFromDoc, remapPos, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutPartForSize };
|
|
1929
|
+
export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CODE55_RAIL_HEIGHT_INCHES, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, 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, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateLead, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, mergeImportedParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, poseNeedsManual, poseOverridesFromDoc, remapPos, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutPartForSize };
|
|
1832
1930
|
//# sourceMappingURL=index.js.map
|
|
1833
1931
|
//# sourceMappingURL=index.js.map
|