【问题标题】:Mathematica: Non-intersecting line segmentsMathematica:不相交的线段
【发布时间】:2011-06-16 07:58:42
【问题描述】:

我们如何告诉 Mathematica 给我们一组不相交的线?在这种情况下,如果两条线有一个共同点(不是端点),则它们相交。考虑这个简单的案例:

l1 = {{-1, 0}, {1, 0}};
l2 = {{0, -1}, {0, 1}};
lines = {l1, l2};

这个想法是创建一个函数,给定一组线,返回一组不相交的线。如果存在这样的函数,比如split,则输出

split[lines]

{
 {{-1, 0}, {0,0}},
 {{ 0, 0}, {1,0}}, 
 {{ 0,-1}, {0,0}}, 
 {{ 0, 0}, {0,1}}
}

该函数检测到{0,0} 是集合中两条线的交点,为了得到不相交的线,它在交点处破坏了线段,从而产生了另外两条线。如果原始输入包含更多行,则此过程会变得更加复杂。有谁知道如何在 Mathematica 中有效地做到这一点而不使用循环?了解一种算法来查找two lines are intersecting 可能会有所帮助。

注意

这个问题是我尝试找出how to make wire frames in Mathematica with hidden line removal 的第二部分。请随意添加更多合适的标签。

【问题讨论】:

  • 我这里没有 Mma,但你想要的是使用标准线性代数将每一行表示为 A.{x, y}=c,并找到两个方程的点线为真,使用 LinearSolve.然后,检查解决方案是否在给定的两条线段的末端之间。如果是这样,请在该点打破线条。与我对您之前问题的回答一样,您希望对 Tuples[Sort[lines],{2}] 执行此操作。
  • @Verbeia,Tuples[Sort[lines], {2}] 应该做什么?让我们假设lines 在我的帖子中被定义。
  • 只有当您有一个要检查的多于两行的列表并且想要检查所有可能的行对时,才需要使用元组函数。它所做的只是从具有两个以上元素的列表中创建所有可能的元素对的列表。下面的 ACL 回答处理重复问题,可能是比元组更好的解决方案。

标签: wolfram-mathematica mathematica-8


【解决方案1】:

如果您假设存在拆分,则需要将其应用于所有对;这些可能由

ClearAll[permsnodups];
permsnodups[lp_] := DeleteDuplicates[Permutations[lp, {2}],
   ((#1[[1]] == #2[[1]]) &&(#1[[2]] == #2[[2]]) || 
   (#1[[1]] == #2[[2]]) && (#1[[2]] == #2[[1]])) &]

执行此操作:permsnodups[{a, b, c, d}] 给出{{a, b}, {a, c}, {a, d}, {b, c}, {b, d}, {c, d}},您可以在其上映射您的split 函数(即这些都是对,确保如果{a,b} 存在则{b,a} 不是从那时起你无缘无故地做两倍的工作——就像做 $\sum_{i,j>i}$ 而不是 $\sum_{i,j}$)。

编辑:这是split 的实现(我被困在半小时左右无法访问互联网,所以手动计算出相关方程式,这不是基于您提供的链接,也不是优化或漂亮):

ClearAll[split2]
split2[{{ai_, bi_}, {ci_, di_}}] := Module[
{g1, g2, a, b, c, d, x0, y0, alpha, beta},
(*make sure that a is to the left of b*)

If[ai[[1]] > bi[[1]], {a, b} = {bi, ai}, {a, b} = {ai, bi}];
If[ci[[1]] > di[[1]], {c, d} = {di, ci}, {c, d} = {ci, di}];
g1 = (b[[2]] - a[[2]])/(b[[1]] - a[[1]]);
g2 = (d[[2]] - c[[2]])/(d[[1]] - c[[1]]);
If[g2 \[Equal] g1,
    {{a, b}, {c, d}},(*they're parallel*)

alpha = a[[2]] - g1*a[[1]];
    beta = c[[2]] - g2*c[[1]];
    x0 = (alpha - beta)/(g2 - g1);(*intersection x*)

If[(a[[1]] < x0 < b[[1]]) && (c[[1]] < x0 < 
   d[[1]]),(*they do intersect*)
            y0 = alpha + g1*x0;
            {{a, #}, {#, b}, {c, #}, {#, d}} &@{x0, y0},
            {{a, b}, {c, d}}(*they don't intersect after all*)]]]

(实际上它非常缓慢和丑陋)。无论如何,你可以看到它是这样工作的:

Manipulate[
Grid[{{Graphics[{Line[{p1, p2}, VertexColors \[Rule] {Red, Green}], 
  Line[{p3, p4}]},
        PlotRange \[Rule] 3, Axes \[Rule] True],
        (*Reap@split2[{{p1,p2},{p3,p4}}]//Last,*)
        If[
            Length@split2[{{p1, p2}, {p3, p4}}] \[Equal] 2,
            "not intersecting",
            "intersecting"]}}],
{{p1, {0, 1}}, Locator}, {{p2, {1, 1}}, Locator},
{{p3, {2.3, -.1}}, Locator}, {{p4, {2, 1}}, Locator}]

产生类似的东西

(您可以移动定位器)。请注意,只要其中一条线是垂直的,我的split2 就会被零除(这可以修复,但我还没有这样做)。

无论如何,这一切都非常缓慢和丑陋。通过编译和使其可列出(并使用您提供的链接)可以使其更快,但我目前的咖啡休息时间已经结束(或半小时前)。我稍后会尝试回到这个问题。

同时,请询问是否有任何具体问题(例如,如果您看不到垂直线的断点)。请注意,虽然这可以满足您的要求,但如果您在行列表上进行映射,您最终会得到一个参差不齐的列表,您必须将其展平。但是,这就是你要求的:)

【讨论】:

  • 您能否快速实现split 以确保完整性?我对 Mathematica 中的映射函数不是很熟悉。很抱歉,如果您使用拆分功能编辑您的答案,您能否将其应用于具有 3 条相交线的示例。说:l1 = {{-1, 0}, {1, 0}}; l2 = {{0, -1}, {0, 1}}; l3 = {{-1,1},{1,1}}; lines = {l1, l2, l3}.
  • 您确实回答了这个问题,但这又带来了另一个问题。我会再考虑一下并在编辑中发布它,因为开始另一个没有意义。
【解决方案2】:

为了确定交点,您还可以执行以下参数化方法,该方法不会遇到涉及笛卡尔方程的方法的常见问题(即除以零......):

f[t_, l_List] := l[[1]] + t (l[[2]] - l[[1]])
split[l1_, l2_] := Module[{s},
  If[(s = ToRules@
       Reduce[f[t1, l1]==f[t2, l2] && 0 <t2< 1 && 0 <t1< 1, {t1,t2},Reals]) =={},
   Return[{l1, l2}],
   Return[{{f[0, l1], f[t1, l1] /. s}, {f[1, l1], f[t1, l1] /. s},
           {f[0, l2], f[t2, l2] /. s}, {f[1, l2], f[t2, l2] /. s}}]
   ]]

【讨论】:

  • 谢谢贝利撒留。这是在交叉点分割线的一种非常好的方法。我有点担心效率。这个函数必须执行很多次。无论如何,我想我可以用你的代码和 acl 提供的代码来解决问题。一旦我有更可靠的案例,我将编辑我的问题。
  • @jmlopez 在我的穷人笔记本电脑中,大约性能是每 10K 路口 8 秒
  • @belisarius 我不认为Reduce 可以编译。我给的那个很笨拙,但至少可以自动编译成C(经过一番按摩)
  • @acl Mine 试图以一种微妙的方式说您的 split2[{{{1, 0}, {-1, 0}}, {{0, 1}, {0, -1}}}] 失败:)
  • @acl 从性能 POV 来看,我确信几乎任何东西都比 Reduce 好:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 2016-08-08
  • 2011-02-20
  • 2011-03-23
  • 2016-07-29
  • 2016-12-22
  • 1970-01-01
相关资源
最近更新 更多