1

Mathematicaに交差しない線のセットを与えるように指示するにはどうすればよいでしょうか? この場合、2 つの線が共通の点 (終点ではない) を持っていれば交差します。この単純なケースを考えてみましょう:

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}は、セット内の 2 つの線の交点を検出し、交差しない線を作成するために、交点で線セグメントを分割して、さらに 2 つの線を生成しました。元の入力にさらに多くの行が含まれている場合、このプロセスはより複雑になります。ループを使用せずにMathematicaでこれを効率的に行う方法を知っている人はいますか? 2 つの線が交差しているかどうかを検出するアルゴリズムを知っていると役立つ場合があります。

ノート

この質問は、隠れ線を削除してMathematicaでワイヤー フレームを作成する方法を見つけようとする私の試みの 2 番目の部分です。適切なタグを自由に追加してください。

4

2 に答える 2

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}is then{b,a}がないことを確認してから、理由もなく 2 倍の作業を行っていることになります。これは $\sum_{i を実行するようなものです)。 $\sum_{i,j}$ ではなく、j>i}$)。

編集:これが実装ですsplit(私は30分ほどインターネットにアクセスできない状態で立ち往生していたので、関連する方程式を手作業で計算しました。これはあなたが提供したリンクに基づいておらず、最適化されていてもきれいでもありません):

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つが垂直である場合は常に0で除算します(これは修正できますが、私は行っていません)。

いずれにせよ、これはすべて非常に遅くて醜いです。コンパイルしてリスト可能にする(そしてあなたが与えたリンクを使用する)ことでより速くすることができますが、私の現在のコーヒーブレイクは終わりました(または30分以上前でした). 後でこれに戻ろうとします。

それまでの間、具体的な質問がないか尋ねてください (たとえば、垂直線の区切りがわからない場合など)。そして、これはあなたが求めることを行いますが、行のリストをマップすると、フラット化する必要がある不規則なリストになることに注意してください。しかし、これはあなたが求めたものです:)

于 2011-06-16T09:45:43.957 に答える
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}}]
   ]]
于 2011-06-17T00:23:11.323 に答える