@willcgage/module-schematic 0.40.0 → 0.42.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 +76 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -2
- package/dist/index.d.ts +60 -2
- package/dist/index.js +73 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* from Next.js (server + client) and Electron alike.
|
|
14
14
|
*/
|
|
15
15
|
type TrackConfig = "single" | "double";
|
|
16
|
-
type TrackRole = "main" | "siding" | "spur" | "yard" | "crossover";
|
|
16
|
+
type TrackRole = "main" | "siding" | "spur" | "yard" | "crossover" | "branch";
|
|
17
17
|
type TurnoutKind = "left" | "right" | "wye";
|
|
18
18
|
type SignalFacing = "AtoB" | "BtoA";
|
|
19
19
|
type SignalSide = "above" | "below";
|
|
@@ -57,6 +57,14 @@ interface SchematicEndplate {
|
|
|
57
57
|
* of the two tracks at its double end. Absent = the recommended default
|
|
58
58
|
* (single centred; double straddling at ∓ half the track spacing). */
|
|
59
59
|
trackOffsetInches?: number | null;
|
|
60
|
+
/** Branch endplates (#170) only — what the route reaching this endplate IS:
|
|
61
|
+
* a secondary "branch" line, or a "main" (a diverging / split main). Drives
|
|
62
|
+
* labels + drawn weight, not geometry. Absent = "branch". */
|
|
63
|
+
kind?: "branch" | "main" | null;
|
|
64
|
+
/** Branch endplates only — the id of the drawn diverging track that reaches
|
|
65
|
+
* this endplate (its authored path ends at the plate face). Lets remove/
|
|
66
|
+
* round-trip pair the endplate with its track. Absent = not yet connected. */
|
|
67
|
+
trackId?: string | null;
|
|
60
68
|
}
|
|
61
69
|
/** Free-moN endplate face width, inches — the connection interface size. */
|
|
62
70
|
declare const FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
|
|
@@ -732,6 +740,12 @@ interface EditorBranch {
|
|
|
732
740
|
pos: number;
|
|
733
741
|
side: "up" | "down";
|
|
734
742
|
config: TrackConfig;
|
|
743
|
+
/** What the route to this endplate is — a secondary "branch" or a diverging
|
|
744
|
+
* "main". Drives labels/weight, not geometry. Default "branch". */
|
|
745
|
+
kind?: "branch" | "main";
|
|
746
|
+
/** The drawn diverging track that reaches this endplate (set when the owner
|
|
747
|
+
* draws track to it; the plate is placed first, connected later). */
|
|
748
|
+
trackId?: string | null;
|
|
735
749
|
}
|
|
736
750
|
/** Endplate B on a loop module: a standard endplate makes the balloon an
|
|
737
751
|
* INTERCHANGE (a second route connects at the loop, e.g. Seaford); "none"
|
|
@@ -1064,6 +1078,50 @@ declare function geometryTurnDegrees(geometryType?: string | null, geometryDegre
|
|
|
1064
1078
|
* side. A `dead_end`/loop module has no B. Overrides replace any derived pose.
|
|
1065
1079
|
*/
|
|
1066
1080
|
declare function deriveEndplatePoses(geo: ModuleGeometryInput): EndplatePose[];
|
|
1081
|
+
/** Free-moN §2.0 — track crossing an endplate must be perpendicular, straight
|
|
1082
|
+
* and level for at least this many inches from the outside face. */
|
|
1083
|
+
declare const ENDPLATE_LEAD_INCHES = 4;
|
|
1084
|
+
/** Free-moN §2.0 — the crossing must stay at least this far from either fascia. */
|
|
1085
|
+
declare const ENDPLATE_FASCIA_CLEAR_INCHES = 4;
|
|
1086
|
+
/** The mandated straight, perpendicular lead a connecting track must follow
|
|
1087
|
+
* leaving an endplate (§2.0). Given the endplate's track point + outward-normal
|
|
1088
|
+
* heading, returns the face point and the point `leadInches` inboard, plus the
|
|
1089
|
+
* inward heading. A track meeting this plate must be collinear with face→inboard
|
|
1090
|
+
* for its first `leadInches`. */
|
|
1091
|
+
declare function endplateLead(pose: {
|
|
1092
|
+
x: number;
|
|
1093
|
+
y: number;
|
|
1094
|
+
heading: number;
|
|
1095
|
+
}, leadInches?: number): {
|
|
1096
|
+
face: BenchworkPoint;
|
|
1097
|
+
inboard: BenchworkPoint;
|
|
1098
|
+
inwardHeading: number;
|
|
1099
|
+
};
|
|
1100
|
+
interface EndplateTrackIssue {
|
|
1101
|
+
/** "not-perpendicular" — the track doesn't cross square to the face;
|
|
1102
|
+
* "short-lead" — it curves/bends within the required lead;
|
|
1103
|
+
* "fascia-clearance" — the crossing is <4″ from a fascia. */
|
|
1104
|
+
code: "not-perpendicular" | "short-lead" | "fascia-clearance";
|
|
1105
|
+
message: string;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Validate a drawn path meeting an endplate against Free-moN §2.0: perpendicular
|
|
1109
|
+
* crossing, straight + level for ≥4″ from the face, ≥4″ from either fascia.
|
|
1110
|
+
* `end` says which end of the authored path touches the plate ("last" default).
|
|
1111
|
+
* Fascia clearance is checked only when both the face width and the track's
|
|
1112
|
+
* offset from the plate centre are supplied. Pure; empty array = compliant.
|
|
1113
|
+
*/
|
|
1114
|
+
declare function trackMeetsEndplateIssues(path: BenchworkPoint[], pose: {
|
|
1115
|
+
x: number;
|
|
1116
|
+
y: number;
|
|
1117
|
+
heading: number;
|
|
1118
|
+
}, opts?: {
|
|
1119
|
+
end?: "first" | "last";
|
|
1120
|
+
faceWidthInches?: number;
|
|
1121
|
+
trackOffsetInches?: number;
|
|
1122
|
+
leadInches?: number;
|
|
1123
|
+
toleranceDeg?: number;
|
|
1124
|
+
}): EndplateTrackIssue[];
|
|
1067
1125
|
/** Whether a module shape's poses are fully derivable, or need manual entry
|
|
1068
1126
|
* (a helpful cue for the authoring UI). */
|
|
1069
1127
|
declare function poseNeedsManual(geometryType?: string | null): boolean;
|
|
@@ -1075,4 +1133,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
1075
1133
|
heading: number;
|
|
1076
1134
|
}>;
|
|
1077
1135
|
|
|
1078
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, 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 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 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, type TrackConfig, type TrackRole, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackPath };
|
|
1136
|
+
export { type BenchworkPoint, type BranchConnector, 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 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 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, type TrackConfig, type TrackRole, 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, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* from Next.js (server + client) and Electron alike.
|
|
14
14
|
*/
|
|
15
15
|
type TrackConfig = "single" | "double";
|
|
16
|
-
type TrackRole = "main" | "siding" | "spur" | "yard" | "crossover";
|
|
16
|
+
type TrackRole = "main" | "siding" | "spur" | "yard" | "crossover" | "branch";
|
|
17
17
|
type TurnoutKind = "left" | "right" | "wye";
|
|
18
18
|
type SignalFacing = "AtoB" | "BtoA";
|
|
19
19
|
type SignalSide = "above" | "below";
|
|
@@ -57,6 +57,14 @@ interface SchematicEndplate {
|
|
|
57
57
|
* of the two tracks at its double end. Absent = the recommended default
|
|
58
58
|
* (single centred; double straddling at ∓ half the track spacing). */
|
|
59
59
|
trackOffsetInches?: number | null;
|
|
60
|
+
/** Branch endplates (#170) only — what the route reaching this endplate IS:
|
|
61
|
+
* a secondary "branch" line, or a "main" (a diverging / split main). Drives
|
|
62
|
+
* labels + drawn weight, not geometry. Absent = "branch". */
|
|
63
|
+
kind?: "branch" | "main" | null;
|
|
64
|
+
/** Branch endplates only — the id of the drawn diverging track that reaches
|
|
65
|
+
* this endplate (its authored path ends at the plate face). Lets remove/
|
|
66
|
+
* round-trip pair the endplate with its track. Absent = not yet connected. */
|
|
67
|
+
trackId?: string | null;
|
|
60
68
|
}
|
|
61
69
|
/** Free-moN endplate face width, inches — the connection interface size. */
|
|
62
70
|
declare const FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
|
|
@@ -732,6 +740,12 @@ interface EditorBranch {
|
|
|
732
740
|
pos: number;
|
|
733
741
|
side: "up" | "down";
|
|
734
742
|
config: TrackConfig;
|
|
743
|
+
/** What the route to this endplate is — a secondary "branch" or a diverging
|
|
744
|
+
* "main". Drives labels/weight, not geometry. Default "branch". */
|
|
745
|
+
kind?: "branch" | "main";
|
|
746
|
+
/** The drawn diverging track that reaches this endplate (set when the owner
|
|
747
|
+
* draws track to it; the plate is placed first, connected later). */
|
|
748
|
+
trackId?: string | null;
|
|
735
749
|
}
|
|
736
750
|
/** Endplate B on a loop module: a standard endplate makes the balloon an
|
|
737
751
|
* INTERCHANGE (a second route connects at the loop, e.g. Seaford); "none"
|
|
@@ -1064,6 +1078,50 @@ declare function geometryTurnDegrees(geometryType?: string | null, geometryDegre
|
|
|
1064
1078
|
* side. A `dead_end`/loop module has no B. Overrides replace any derived pose.
|
|
1065
1079
|
*/
|
|
1066
1080
|
declare function deriveEndplatePoses(geo: ModuleGeometryInput): EndplatePose[];
|
|
1081
|
+
/** Free-moN §2.0 — track crossing an endplate must be perpendicular, straight
|
|
1082
|
+
* and level for at least this many inches from the outside face. */
|
|
1083
|
+
declare const ENDPLATE_LEAD_INCHES = 4;
|
|
1084
|
+
/** Free-moN §2.0 — the crossing must stay at least this far from either fascia. */
|
|
1085
|
+
declare const ENDPLATE_FASCIA_CLEAR_INCHES = 4;
|
|
1086
|
+
/** The mandated straight, perpendicular lead a connecting track must follow
|
|
1087
|
+
* leaving an endplate (§2.0). Given the endplate's track point + outward-normal
|
|
1088
|
+
* heading, returns the face point and the point `leadInches` inboard, plus the
|
|
1089
|
+
* inward heading. A track meeting this plate must be collinear with face→inboard
|
|
1090
|
+
* for its first `leadInches`. */
|
|
1091
|
+
declare function endplateLead(pose: {
|
|
1092
|
+
x: number;
|
|
1093
|
+
y: number;
|
|
1094
|
+
heading: number;
|
|
1095
|
+
}, leadInches?: number): {
|
|
1096
|
+
face: BenchworkPoint;
|
|
1097
|
+
inboard: BenchworkPoint;
|
|
1098
|
+
inwardHeading: number;
|
|
1099
|
+
};
|
|
1100
|
+
interface EndplateTrackIssue {
|
|
1101
|
+
/** "not-perpendicular" — the track doesn't cross square to the face;
|
|
1102
|
+
* "short-lead" — it curves/bends within the required lead;
|
|
1103
|
+
* "fascia-clearance" — the crossing is <4″ from a fascia. */
|
|
1104
|
+
code: "not-perpendicular" | "short-lead" | "fascia-clearance";
|
|
1105
|
+
message: string;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Validate a drawn path meeting an endplate against Free-moN §2.0: perpendicular
|
|
1109
|
+
* crossing, straight + level for ≥4″ from the face, ≥4″ from either fascia.
|
|
1110
|
+
* `end` says which end of the authored path touches the plate ("last" default).
|
|
1111
|
+
* Fascia clearance is checked only when both the face width and the track's
|
|
1112
|
+
* offset from the plate centre are supplied. Pure; empty array = compliant.
|
|
1113
|
+
*/
|
|
1114
|
+
declare function trackMeetsEndplateIssues(path: BenchworkPoint[], pose: {
|
|
1115
|
+
x: number;
|
|
1116
|
+
y: number;
|
|
1117
|
+
heading: number;
|
|
1118
|
+
}, opts?: {
|
|
1119
|
+
end?: "first" | "last";
|
|
1120
|
+
faceWidthInches?: number;
|
|
1121
|
+
trackOffsetInches?: number;
|
|
1122
|
+
leadInches?: number;
|
|
1123
|
+
toleranceDeg?: number;
|
|
1124
|
+
}): EndplateTrackIssue[];
|
|
1067
1125
|
/** Whether a module shape's poses are fully derivable, or need manual entry
|
|
1068
1126
|
* (a helpful cue for the authoring UI). */
|
|
1069
1127
|
declare function poseNeedsManual(geometryType?: string | null): boolean;
|
|
@@ -1075,4 +1133,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
1075
1133
|
heading: number;
|
|
1076
1134
|
}>;
|
|
1077
1135
|
|
|
1078
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, 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 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 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, type TrackConfig, type TrackRole, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackPath };
|
|
1136
|
+
export { type BenchworkPoint, type BranchConnector, 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 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 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, type TrackConfig, type TrackRole, 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, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPath };
|
package/dist/index.js
CHANGED
|
@@ -615,7 +615,11 @@ function buildTransition(state) {
|
|
|
615
615
|
// Branton, #131). Main 1 runs the full module; Main 2 is the branch.
|
|
616
616
|
onTrack: MAIN_TRACK_ID,
|
|
617
617
|
divergeTrack: MAIN2_TRACK_ID,
|
|
618
|
-
|
|
618
|
+
// Hand so the diverging leg lands on Main 2's side. Main 2 extends toward
|
|
619
|
+
// the double end (sign −1 west / +1 east) and sits above (+1) or, when the
|
|
620
|
+
// mains are swapped, below (−1). divergeSideForHand(left)=sign(toward),
|
|
621
|
+
// (right)=−sign(toward), so pick the hand whose side matches Main 2's (#131).
|
|
622
|
+
kind: (aDouble ? -1 : 1) === (state.mainsSwapped ? -1 : 1) ? "left" : "right"
|
|
619
623
|
};
|
|
620
624
|
const cpId = nextId("cp", state.controlPoints.map((c) => c.id));
|
|
621
625
|
const sig = (facing) => ({
|
|
@@ -689,7 +693,9 @@ function stateToDoc(state, recordNumber) {
|
|
|
689
693
|
// C, D, E…
|
|
690
694
|
label: b.label || `Branch ${i + 1}`,
|
|
691
695
|
tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: b.config }],
|
|
692
|
-
at: { pos: b.pos, side: b.side }
|
|
696
|
+
at: { pos: b.pos, side: b.side },
|
|
697
|
+
kind: b.kind ?? "branch",
|
|
698
|
+
...b.trackId ? { trackId: b.trackId } : {}
|
|
693
699
|
}))
|
|
694
700
|
],
|
|
695
701
|
state.poseOverrides
|
|
@@ -891,7 +897,9 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
891
897
|
label: ep.label ?? "Branch",
|
|
892
898
|
pos: sc(ep.at.pos),
|
|
893
899
|
side: ep.at.side === "down" ? "down" : "up",
|
|
894
|
-
config: ep.tracks?.[0]?.config === "double" ? "double" : "single"
|
|
900
|
+
config: ep.tracks?.[0]?.config === "double" ? "double" : "single",
|
|
901
|
+
kind: ep.kind === "main" ? "main" : "branch",
|
|
902
|
+
trackId: ep.trackId ?? null
|
|
895
903
|
})),
|
|
896
904
|
poseOverrides,
|
|
897
905
|
endplateWidths,
|
|
@@ -1401,6 +1409,67 @@ function deriveEndplatePoses(geo) {
|
|
|
1401
1409
|
}
|
|
1402
1410
|
return poses;
|
|
1403
1411
|
}
|
|
1412
|
+
var ENDPLATE_LEAD_INCHES = 4;
|
|
1413
|
+
var ENDPLATE_FASCIA_CLEAR_INCHES = 4;
|
|
1414
|
+
function endplateLead(pose, leadInches = ENDPLATE_LEAD_INCHES) {
|
|
1415
|
+
const inwardHeading = norm360(pose.heading + 180);
|
|
1416
|
+
const r = inwardHeading * DEG;
|
|
1417
|
+
return {
|
|
1418
|
+
face: { x: pose.x, y: pose.y },
|
|
1419
|
+
inboard: { x: pose.x + Math.cos(r) * leadInches, y: pose.y + Math.sin(r) * leadInches },
|
|
1420
|
+
inwardHeading
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
function trackMeetsEndplateIssues(path, pose, opts) {
|
|
1424
|
+
const issues = [];
|
|
1425
|
+
const lead = opts?.leadInches ?? ENDPLATE_LEAD_INCHES;
|
|
1426
|
+
const tol = opts?.toleranceDeg ?? 5;
|
|
1427
|
+
if (path && path.length >= 2) {
|
|
1428
|
+
const seq = (opts?.end ?? "last") === "last" ? [...path].reverse() : path.slice();
|
|
1429
|
+
const p0 = seq[0];
|
|
1430
|
+
const p1 = seq[1];
|
|
1431
|
+
const wantIn = norm360(pose.heading + 180);
|
|
1432
|
+
const inHead = norm360(Math.atan2(p1.y - p0.y, p1.x - p0.x) / DEG);
|
|
1433
|
+
const diff = Math.abs((inHead - wantIn + 540) % 360 - 180);
|
|
1434
|
+
if (diff > tol)
|
|
1435
|
+
issues.push({
|
|
1436
|
+
code: "not-perpendicular",
|
|
1437
|
+
message: `Track must cross the endplate square (within ${tol}\xB0); it is off by ${Math.round(diff)}\xB0.`
|
|
1438
|
+
});
|
|
1439
|
+
const r = wantIn * DEG;
|
|
1440
|
+
const ux = Math.cos(r);
|
|
1441
|
+
const uy = Math.sin(r);
|
|
1442
|
+
let curved = false;
|
|
1443
|
+
let acc = 0;
|
|
1444
|
+
for (let i = 1; i < seq.length && acc < lead; i++) {
|
|
1445
|
+
const a = seq[i - 1];
|
|
1446
|
+
const b = seq[i];
|
|
1447
|
+
if (a.bulge) curved = true;
|
|
1448
|
+
const rx = b.x - p0.x;
|
|
1449
|
+
const ry = b.y - p0.y;
|
|
1450
|
+
const along = rx * ux + ry * uy;
|
|
1451
|
+
const lat = Math.abs(rx * -uy + ry * ux);
|
|
1452
|
+
if (along <= lead + 0.01 && lat > 0.25) curved = true;
|
|
1453
|
+
acc += Math.hypot(b.x - a.x, b.y - a.y);
|
|
1454
|
+
}
|
|
1455
|
+
if (curved)
|
|
1456
|
+
issues.push({
|
|
1457
|
+
code: "short-lead",
|
|
1458
|
+
message: `The first ${lead}\u2033 from the endplate must be straight and perpendicular.`
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
const w = opts?.faceWidthInches;
|
|
1462
|
+
const off = opts?.trackOffsetInches;
|
|
1463
|
+
if (typeof w === "number" && w > 0 && typeof off === "number") {
|
|
1464
|
+
const clear = w / 2 - Math.abs(off);
|
|
1465
|
+
if (clear < ENDPLATE_FASCIA_CLEAR_INCHES)
|
|
1466
|
+
issues.push({
|
|
1467
|
+
code: "fascia-clearance",
|
|
1468
|
+
message: `Track must stay \u2265${ENDPLATE_FASCIA_CLEAR_INCHES}\u2033 from either fascia; it is ${clear.toFixed(1)}\u2033.`
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
return issues;
|
|
1472
|
+
}
|
|
1404
1473
|
function poseNeedsManual(geometryType) {
|
|
1405
1474
|
return geometryType === "wye" || geometryType === "other";
|
|
1406
1475
|
}
|
|
@@ -1414,6 +1483,6 @@ function poseOverridesFromDoc(doc) {
|
|
|
1414
1483
|
return out;
|
|
1415
1484
|
}
|
|
1416
1485
|
|
|
1417
|
-
export { 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, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackPath };
|
|
1486
|
+
export { 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, 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, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackMeetsEndplateIssues, trackPath };
|
|
1418
1487
|
//# sourceMappingURL=index.js.map
|
|
1419
1488
|
//# sourceMappingURL=index.js.map
|