@willcgage/module-schematic 0.29.0 → 0.30.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 CHANGED
@@ -21,10 +21,17 @@ function moduleSections(doc) {
21
21
  return (doc?.sections ?? []).filter((sec) => sec && typeof sec.id === "string" && sec.id !== "").map((sec) => {
22
22
  const outline = benchworkOutline({ outline: sec.outline });
23
23
  const name = typeof sec.name === "string" ? sec.name.trim() : "";
24
+ const len = sec.lengthInches;
25
+ const deg = sec.geometryDegrees;
26
+ const off = sec.geometryOffsetInches;
24
27
  return {
25
28
  id: sec.id,
26
29
  ...name ? { name } : {},
27
- ...outline ? { outline } : {}
30
+ ...outline ? { outline } : {},
31
+ ...typeof len === "number" && Number.isFinite(len) && len > 0 ? { lengthInches: len } : {},
32
+ ...sec.geometryType ? { geometryType: sec.geometryType } : {},
33
+ ...typeof deg === "number" && Number.isFinite(deg) ? { geometryDegrees: deg } : {},
34
+ ...typeof off === "number" && Number.isFinite(off) ? { geometryOffsetInches: off } : {}
28
35
  };
29
36
  });
30
37
  }
@@ -128,6 +135,8 @@ var DEG_FP = Math.PI / 180;
128
135
  function moduleCenterline(input) {
129
136
  const drawn = trackPath(input.mainPath);
130
137
  if (drawn) return samplePath(drawn);
138
+ const chained = sectionedCenterline(input);
139
+ if (chained.length >= 2) return chained;
131
140
  if (!input.geometryType) return [];
132
141
  const L = input.lengthInches > 0 ? input.lengthInches : 24;
133
142
  const gt = input.geometryType;
@@ -145,6 +154,73 @@ function moduleCenterline(input) {
145
154
  }
146
155
  return pts;
147
156
  }
157
+ function sectionCenterlineLocal(sec) {
158
+ const L = typeof sec.lengthInches === "number" && sec.lengthInches > 0 ? sec.lengthInches : 0;
159
+ const gt = sec.geometryType || "straight";
160
+ if (L <= 0) return { points: [{ x: 0, y: 0 }], endX: 0, endY: 0, endHeadingDeg: 0 };
161
+ if (gt === "offset") {
162
+ const dy = sec.geometryOffsetInches ?? 0;
163
+ return { points: [{ x: 0, y: 0 }, { x: L, y: dy }], endX: L, endY: dy, endHeadingDeg: 0 };
164
+ }
165
+ const turn = gt === "corner_45" ? 45 : gt === "corner_90" ? 90 : gt === "curve" ? sec.geometryDegrees ?? 0 : 0;
166
+ if (turn === 0) return { points: [{ x: 0, y: 0 }, { x: L, y: 0 }], endX: L, endY: 0, endHeadingDeg: 0 };
167
+ const t = turn * DEG_FP;
168
+ const r = L / t;
169
+ const steps = 12;
170
+ const points = [];
171
+ for (let i = 0; i <= steps; i++) {
172
+ const a = t * i / steps;
173
+ points.push({ x: r * Math.sin(a), y: r * (1 - Math.cos(a)) });
174
+ }
175
+ const last = points[points.length - 1];
176
+ return { points, endX: last.x, endY: last.y, endHeadingDeg: turn };
177
+ }
178
+ function moduleLengthFromSections(doc) {
179
+ const secs = moduleSections(doc).filter(
180
+ (sec) => typeof sec.lengthInches === "number" && sec.lengthInches > 0
181
+ );
182
+ if (!secs.length) return null;
183
+ return secs.reduce((a, sec) => a + sec.lengthInches, 0);
184
+ }
185
+ function sectionSpans(doc) {
186
+ let acc = 0;
187
+ const out = [];
188
+ for (const sec of moduleSections(doc)) {
189
+ const L = typeof sec.lengthInches === "number" && sec.lengthInches > 0 ? sec.lengthInches : 0;
190
+ if (L <= 0) continue;
191
+ out.push({ id: sec.id, ...sec.name ? { name: sec.name } : {}, fromPos: acc, toPos: acc + L });
192
+ acc += L;
193
+ }
194
+ return out;
195
+ }
196
+ function sectionBreaksFromSections(doc) {
197
+ const spans = sectionSpans(doc);
198
+ return spans.slice(0, -1).map((sp) => sp.toPos);
199
+ }
200
+ function sectionedCenterline(doc) {
201
+ const secs = moduleSections(doc).filter(
202
+ (sec) => typeof sec.lengthInches === "number" && sec.lengthInches > 0
203
+ );
204
+ if (!secs.length) return [];
205
+ const out = [];
206
+ let ox = 0;
207
+ let oy = 0;
208
+ let heading = 0;
209
+ for (const sec of secs) {
210
+ const local = sectionCenterlineLocal(sec);
211
+ const c = Math.cos(heading * DEG_FP);
212
+ const sn = Math.sin(heading * DEG_FP);
213
+ for (let i = 0; i < local.points.length; i++) {
214
+ if (i === 0 && out.length) continue;
215
+ const p = local.points[i];
216
+ out.push({ x: ox + p.x * c - p.y * sn, y: oy + p.x * sn + p.y * c });
217
+ }
218
+ ox += local.endX * c - local.endY * sn;
219
+ oy += local.endX * sn + local.endY * c;
220
+ heading += local.endHeadingDeg;
221
+ }
222
+ return out;
223
+ }
148
224
  function centerlineNormals(center) {
149
225
  return center.map((_, i) => {
150
226
  const a = center[Math.max(0, i - 1)];
@@ -1149,6 +1225,7 @@ exports.isTransitionTurnout = isTransitionTurnout;
1149
1225
  exports.moduleCenterline = moduleCenterline;
1150
1226
  exports.moduleFeatures = moduleFeatures;
1151
1227
  exports.moduleFootprint = moduleFootprint;
1228
+ exports.moduleLengthFromSections = moduleLengthFromSections;
1152
1229
  exports.moduleSections = moduleSections;
1153
1230
  exports.nextId = nextId;
1154
1231
  exports.poseNeedsManual = poseNeedsManual;
@@ -1156,7 +1233,10 @@ exports.poseOverridesFromDoc = poseOverridesFromDoc;
1156
1233
  exports.sampleBenchworkOutline = sampleBenchworkOutline;
1157
1234
  exports.samplePath = samplePath;
1158
1235
  exports.scaleFeetToInches = scaleFeetToInches;
1236
+ exports.sectionBreaksFromSections = sectionBreaksFromSections;
1159
1237
  exports.sectionFootprints = sectionFootprints;
1238
+ exports.sectionSpans = sectionSpans;
1239
+ exports.sectionedCenterline = sectionedCenterline;
1160
1240
  exports.stateToDoc = stateToDoc;
1161
1241
  exports.trackPath = trackPath;
1162
1242
  //# sourceMappingURL=index.cjs.map