我们怎样才能告诉 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的第二部分。请随意添加更合适的标签。
答案 0 :(得分:3)
如果您认为存在拆分,则需要将其应用于所有对;
可能会产生这些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
除以零(这可以修复,但我还没有完成)。
无论如何,这都是非常缓慢和丑陋的。它可以通过编译和制作可列表(并使用你给出的链接)来加快速度,但我目前的咖啡休息时间已经结束(或超过半小时前)。我稍后会尝试回到这里。
同时,请问是否有任何具体问题(例如,如果你看不到垂直线的断裂)。请注意,虽然这样做符合您的要求,但如果您确实在一个行列表上进行映射,您最终会得到一个粗糙的列表,您必须将其展平。但是,这就是你要求的:)
答案 1 :(得分: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}}]
]]