class SegmentJoiner {
constructor(segments) {
if (!segments)
throw Error("Missing required argument to parameter 'segments'");
if (!(segments instanceof Array))
throw "Argument to parameter 'segments' must be an array";
this.segments = segments;
this.segmentsCopy = segments.map((d) => d.map((e) => [...e]));
this.segmentMap = this.groupBySegment(segments);
this.weldMap = this.groupByWelds(segments);
this.weldMapCopy = this.groupByWelds(segments);
this.orderedIndicesPerLine = new Map();
this.startSegments = this.findStartSegments();
}
get() {
return this.weldMap;
}
get getWeldMap() {
return this.weldMap;
}
get getWeldMapCopy() {
return this.weldMapCopy;
}
get getSegmentMap() {
return this.segmentMap;
}
groupBySegment(segments) {
const startEndPerSegment = new d3.InternMap([], JSON.stringify);
segments.forEach((coords, i) => {
const start = coords[0];
const { length } = coords;
const end = coords[length - 1];
startEndPerSegment.set(i, { start, end });
});
return startEndPerSegment;
}
groupByWelds(segments) {
const coordsMap = new d3.InternMap([], JSON.stringify);
segments.map((coords, i) => {
const { length } = coords;
const startNode = coords[0];
const endNode = coords[length - 1];
if (coordsMap.has(startNode)) {
if (coordsMap.get(startNode).has("startOf")) {
coordsMap.get(startNode).set("alsoStartOf", i);
} else {
coordsMap.get(startNode).set("startOf", i);
}
} else {
coordsMap.set(startNode, new Map([["startOf", i]]));
}
if (coordsMap.has(endNode)) {
if (coordsMap.get(endNode).has("endOf")) {
coordsMap.get(endNode).set("alsoEndOf", i);
} else {
coordsMap.get(endNode).set("endOf", i);
}
} else {
coordsMap.set(endNode, new Map([["endOf", i]]));
}
});
return coordsMap;
}
findStartSegments() {
const starts = [];
for (const [coord, startEndOfSegmentMap] of this.weldMapCopy) {
if (startEndOfSegmentMap.size === 1) {
if (startEndOfSegmentMap.has("startOf")) {
starts.push({
index: startEndOfSegmentMap.get("startOf"),
reverse: false
});
console.log("start segment:", startEndOfSegmentMap.get("startOf"));
}
}
}
for (const [coord, startEndOfSegmentMap] of this.weldMapCopy) {
if (startEndOfSegmentMap.size === 1) {
if (startEndOfSegmentMap.has("endOf")) {
console.log(
"Reversed, segment has no startOf at ends",
startEndOfSegmentMap.get("endOf")
);
starts.push({
index: startEndOfSegmentMap.get("endOf"),
reverse: true
});
}
}
}
return starts;
}
findNextSegment(weld, prevSegment) {
if (!weld || !prevSegment) {
return "Not enough args to findNextSegment :(";
}
console.log(
"finding next segment of weld",
{ weld },
"with prev segment",
prevSegment
);
const segmentsOfWeld = this.weldMap.get(weld);
for (const [termination, segmentIndex] of segmentsOfWeld) {
console.log(termination, prevSegment.index);
if (segmentIndex === prevSegment.index) {
console.log("Remove previous segment index", segmentIndex);
segmentsOfWeld.delete(termination);
}
}
if (segmentsOfWeld.has("startOf")) {
console.log("Normal direction");
const index = segmentsOfWeld.get("startOf");
segmentsOfWeld.delete("startOf");
return { index, reverse: false };
}
if (segmentsOfWeld.has("endOf")) {
console.log("Reverse direction");
const index = segmentsOfWeld.get("endOf");
segmentsOfWeld.delete("endOf");
return { index, reverse: true };
}
if (segmentsOfWeld.has("alsoStartOf")) {
console.log("Again normal direction");
const index = segmentsOfWeld.get("alsoStartOf");
segmentsOfWeld.delete("alsoStartOf");
return { index, reverse: false };
}
if (segmentsOfWeld.has("alsoEndOf")) {
console.log("Again reverse direction");
const index = segmentsOfWeld.get("alsoEndOf");
segmentsOfWeld.delete("alsoEndOf");
return { index, reverse: true };
}
return false;
}
findNextWeld(segment) {
console.log("finding next weld of segment", segment);
const nextWeld = this.segmentMap.get(segment.index);
if (!segment.reverse) return nextWeld.end;
return nextWeld.start;
}
joinSegments(currentWeld, currentSegmentIndex, i) {
let nextSegment = this.findNextSegment(currentWeld, currentSegmentIndex);
if (nextSegment === false) {
console.log(
`Segment with index ${currentSegmentIndex.index} is is the final segment of this Line`
);
return;
}
this.orderedIndicesPerLine.get(i).push(nextSegment);
let nextWeld = this.findNextWeld(nextSegment);
this.joinSegments(nextWeld, nextSegment, i);
}
joinAllSegments() {
this.startSegments.forEach((firstSegmentIndex, i) => {
const firstWeld = this.findNextWeld(firstSegmentIndex);
this.orderedIndicesPerLine.set(i, [firstSegmentIndex]);
this.joinSegments(firstWeld, firstSegmentIndex, i);
});
return this.orderedIndicesPerLine;
}
orderAndMergeSegments() {
const orderedLines = [];
console.log("orderAndMergeSegments");
for (const [i, sortedIndices] of this.orderedIndicesPerLine) {
console.log({ i, sortedIndices });
const orderedLine = sortedIndices
.map((seg) => {
if (seg.reverse) {
const reverseSeg = this.segments[seg.index].map((d) => [...d]);
console.log({ reverseSeg });
return reverseSeg.reverse();
}
return this.segments[seg.index];
})
.flat();
orderedLines.push(orderedLine);
}
return orderedLines;
}
}