英文:
How can I find out if multiple lines overlap?
问题
在上面的图片中,如果线段重叠,可以将其视为一条线段。解决这个问题的数学逻辑是找出不重叠的线段,输出的结果是[3,4],[5,4]和[8,4],[20,4]这两个不重叠的线段。
我提供的输入只包括3个线段,我们需要过滤出不重叠的线段。如果线段更多,没有适当的数学方法的话,这个问题会变得更加复杂。我之所以这样做是因为在我的编程中遇到了这个问题。
我尝试的解决方法是使用以下逻辑来判断两条线是否重叠:A.start <= B.end && B.start <= A.end
,如这里所述。我目前卡住了这个问题的代码已经发布在codepen的在线演示这里。
英文:
Each line segment has 2 xy coordinates given,
Input are below,
[3,4],[5,4]
[8,4],[20,4]
[10,4],[15,4]
In the above picture, if the lines are overlapping, it can be considered as a line segment. May I know the logic or mathematics behind solving it which outputs the 2 non-overlapping line segments which are [3,4],[5,4] and [8,4],[20,4]?
The input I gave is just 3 line segments that we have to filter out to non-overlapping line segments, so this gets complicated fast with more line segments if we don't have the proper mathematics. I am doing this because I faced this bug in my programming :).
I will appreciate any help that I can obtain
My solution is I have tried to find whether 2 lines are overlapping from by using some of the logic which is A.start <= B.end && B.start <= A.end
as stated in here. The current code which I am stuck on this problem is published in codepen live demo here.
答案1
得分: 1
您的绘图表明您正在使用二维数据点,具有x和y坐标。在2D中找到重叠的线需要比仅仅检查起始和结束点更复杂的逻辑。
然而,由于您的示例是1D的,我将处理那部分。
在这个解决方案中,您需要按增加的起始坐标对每个线段进行迭代。当您遇到每个后续线段时,您可以选择将它们合并或添加新的线段,具体取决于它们是否重叠。
function resolveOverlaps(lines) {
if (lines.length <= 1) return lines;
if (lines[0].length !== 2 || typeof lines[0][0] !== "number") {
throw new Error(
"无效的输入形状。resolveOverlaps需要一个类似`[[start0, end0], ..., [startN, endN]]`的N元组列表。"
);
}
for (const line of lines) {
if (line[0] > line[1]) {
throw new Error(
`无效的线段 [${line[0]}, ${line[1]}]。确保起始 <= 结束。`
);
}
}
// 按起始值升序对线段进行排序
lines.sort((a, b) => a[0][0] - b[0][0]);
let outLines = [lines[0]];
let last = outLines[0];
// 遍历线段,跳过第一个
lines.slice(1).forEach((line) => {
// 有重叠,扩展当前线段的结束
if (line[0][0] <= last[1][0]) {
last[1][0] = Math.max(last[1][0], line[1][0]);
} else {
// 无重叠,开始一个新线段
outLines.push(line);
last = outLines[outLines.length - 1];
}
});
return outLines;
}
编辑:这是一个用于2D线段的实现,假设所有点都位于同一条直线上,因此只需要检查每个点的x坐标。一般的2D解决方案需要比这更复杂的逻辑。
function resolveOverlaps2d(lines) {
if (lines.length <= 1) return lines;
if (lines[0].length !== 2 || lines[0][0].length !== 2) {
throw an Error(
"无效的输入形状。resolveOverlaps需要一个类似`[[[x0_0, y0_0], [x0_1, y0_1]], ..., [[xN_0, yN_0], [xN_1, yN_1]]]`的N元组列表。"
);
}
for (const line of lines) {
if (line[0][0] > line[1][0]) {
throw an Error(
`无效的线段 [${line[0]}, ${line[1]}]。确保起始 <= 结束。`
);
}
}
// 按起始值升序对线段进行排序
lines.sort((a, b) => a[0][0] - b[0][0]);
let outLines = [lines[0]];
let last = outLines[0];
// 遍历线段,跳过第一个
lines.slice(1).forEach((line) => {
// 有重叠,扩展当前线段的结束
if (line[0][0] <= last[1][0]) {
last[1][0] = Math.max(last[1][0], line[1][0]);
} else {
// 无重叠,开始一个新线段
outLines.push(line);
last = outLines[outLines.length - 1];
}
});
return outLines;
}
英文:
Your drawing indicates that you're using two-dimensional data points, with x and y coordinates. Finding overlapping lines in 2D requires more sophisticated logic than just checking start and end points.
However, as your sandbox example is 1D, I'll address that.
In this solution, you iterate over each of the line segments, sorted by increasing start coordinate. As you encounter each subsequent segment, you choose to either combine the two or add a new segment, depending on whether they overlap or not.
function resolveOverlaps(lines) {
if (lines.length <= 1) return lines;
if (lines[0].length !== 2 || typeof lines[0][0] !== "number") {
throw new Error(
"Invalid input shape. resolveOverlaps requires a list of N tuples like `[[start0, end0], ..., [startN, endN]]`"
);
}
for (const line of lines) {
if (line[0] > line[1]) {
throw new Error(
`Invalid segment [${line[0]}, ${line[1]}]. Ensure startend.`
);
}
}
// Sort the lines ascending by start value
lines.sort((a, b) => a[0][0] - b[0][0]);
let outLines = [lines[0]];
let last = outLines[0];
// Iterate over the lines, skipping the first one
lines.slice(1).forEach((line) => {
// There's an overlap, so extend the current segment's end
if (line[0][0] <= last[1][0]) {
last[1][0] = Math.max(last[1][0], line[1][0]);
} else {
// No overlap, start a new segment
outLines.push(line);
last = outLines[outLines.length - 1];
}
});
return outLines;
}
Edit: Here's an implementation for 2D segments which assumes that all points lie on the same line, and thus only needs to check the x coordinate of each point. A general 2D solution requires more sophisticated logic than this.
function resolveOverlaps2d(lines) {
if (lines.length <= 1) return lines;
if (lines[0].length !== 2 || lines[0][0].length !== 2) {
throw new Error(
"Invalid input shape. resolveOverlaps requires a list of N tuples like `[[[x0_0, y0_0], [x0_1, y0_1]], ..., [[xN_0, yN_0], [xN_1, yN_1]]]"
);
}
for (const line of lines) {
if (line[0][0] > line[1][0]) {
throw new Error(
`Invalid segment [${line[0]}, ${line[1]}]. Ensure start <= end.`
);
}
}
// Sort the lines ascending by start value
lines.sort((a, b) => a[0][0] - b[0][0]);
let outLines = [lines[0]];
let last = outLines[0];
// Iterate over the lines, skipping the first one
lines.slice(1).forEach((line) => {
// There's an overlap, so extend the current segment's end
if (line[0][0] <= last[1][0]) {
last[1][0] = Math.max(last[1][0], line[1][0]);
} else {
// No overlap, start a new segment
outLines.push(line);
last = outLines[outLines.length - 1];
}
});
return outLines;
}
答案2
得分: 1
我审查了代码,发现逻辑没有问题。问题出在维度和输入上。
这是修改后的代码。
function resolveOverlaps(lines) {
if (lines.length <= 1) return lines;
// 按起始值升序排序线段
lines.sort((a, b) => a[0][0] - b[0][0]);
let outLines = [lines[0]];
let last = outLines[0];
// 遍历线段,跳过第一个
lines.slice(1).forEach((line) => {
// 存在重叠,扩展当前段的结束
if (line[0][0] <= last[1][0]) {
last[1][0] = Math.max(last[1][0], line[1][0]);
} else {
// 没有重叠,开始一个新的段
outLines.push(line);
last = outLines[outLines.length - 1];
}
});
return outLines;
}
英文:
I reviewed the code and found there was nothing wrong with the logic. The problem was with the dimensions and input.
Here's the revised code.
function resolveOverlaps(lines) {
if (lines.length <= 1) return lines;
// Sort the lines ascending by start value
lines.sort((a, b) => a[0][0] - b[0][0]);
let outLines = [lines[0]];
let last = outLines[0];
// Iterate over the lines, skipping the first one
lines.slice(1).forEach((line) => {
// There's an overlap, so extend the current segment's end
if (line[0][0] <= last[1][0]) {
last[1][0] = Math.max(last[1][0], line[1][0]);
} else {
// No overlap, start a new segment
outLines.push(line);
last = outLines[outLines.length - 1];
}
});
return outLines;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论