質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

2942閲覧

C#でドロネーグラフから三角形分割を取得したい

KEEL

総合スコア52

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2020/12/10 09:21

編集2020/12/11 12:36

目的

Unityにおいてメッシュを切断するためドロネー三角形分割を実装しました。
ドロネーグラフ(ドロネー木)の実装のため以下の情報を参考にして非巡回有効グラフ(DAG)を実装しました。
An Extensive Examination of Data Structures Using C# 2.0 Part3
An Extensive Examination of Data Structures Using C# 2.0 Part5

ドロネーグラフの接続先が無いノードを重複無しで取り出すことができれば三角形分割を取り出すことができます。

#対応
そこでグラフの全要素を重複無しで取り出すために以下のような実装をしました。

  • グラフに全ノードを格納するリストを作る。
  • ノード追加(AddDirectedEdge)時に全ノードリストにあるノードと重複するか確認する。
  • 重複していなければ全ノードリストに格納、そうでない場合は何もしない。

#問題
前述の方法ではノード追加時の重複チェックにO(n)の計算量を必要とします。(nはグラフのノード数)
ノード追加は頻繁に行うため、できれば定数時間に落としたいです。
また、O(n)程度でDAGの重複無し全要素を取得するアルゴリズムがあればお教えいただきたいです。

#実装
この実装は以下の実装から重みを省いて前述の対応を追加したものです。
An Extensive Examination of Data Structures Using C# 2.0 Part3
An Extensive Examination of Data Structures Using C# 2.0 Part5

C#

1using System.Collections; 2using System.Collections.Generic; 3public class Graph<T> : IEnumerable<T> 4{ 5 private NodeList<T> nodeSet; 6 public NodeList<T> allNode = new NodeList<T>(); 7 8 public Graph() : this(null) { } 9 public Graph(NodeList<T> nodeSet) 10 { 11 if (nodeSet == null) 12 this.nodeSet = new NodeList<T>(); 13 else 14 this.nodeSet = nodeSet; 15 } 16 public void AddNode(GraphNode<T> node) 17 { 18 nodeSet.Add(node); 19 allNode.Add(node); 20 } 21 public void AddNode(T value) 22 { 23 nodeSet.Add(new GraphNode<T>(value)); 24 } 25 public void AddDirectedEdge(GraphNode<T> from, GraphNode<T> to) 26 { 27 from.Neighbors.Add(to); 28 if (!allNode.Contains(to)) 29 allNode.Add(to); 30 } 31 public bool Contains(T value) 32 { 33 return nodeSet.FindByValue(value) != null; 34 } 35 public bool Remove(T value) 36 { 37 GraphNode<T> nodeToRemove = (GraphNode<T>)nodeSet.FindByValue(value); 38 if (nodeToRemove == null) 39 return false; 40 41 nodeSet.Remove(nodeToRemove); 42 43 foreach (GraphNode<T> gnode in nodeSet) 44 { 45 int index = gnode.Neighbors.IndexOf(nodeToRemove); 46 if (index != -1) 47 gnode.Neighbors.RemoveAt(index); 48 } 49 50 return true; 51 } 52 public IEnumerator<T> GetEnumerator() 53 { 54 return (IEnumerator<T>)allNode.GetEnumerator(); 55 } 56 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 57 public NodeList<T> NodeList 58 { 59 get { return nodeSet; } 60 } 61}

C#

1public class GraphNode<T> : Node<T> 2{ 3 public GraphNode() : base() { } 4 public GraphNode(T value) : base(value) { } 5 public GraphNode(T value, NodeList<T> neighbors) : base(value, neighbors) { } 6 7 new public NodeList<T> Neighbors 8 { 9 get 10 { 11 if (base.Neighbors == null) 12 base.Neighbors = new NodeList<T>(); 13 return base.Neighbors; 14 } 15 } 16}

C#

1public class Node<T> 2{ 3 private T data; 4 private NodeList<T> neighbors = null; 5 6 public Node() { } 7 public Node(T data) : this(data, null) { } 8 public Node(T data, NodeList<T> neighbors) 9 { 10 this.data = data; 11 this.neighbors = neighbors; 12 } 13 public T Value 14 { 15 get 16 { 17 return data; 18 } 19 set 20 { 21 data = value; 22 } 23 } 24 protected NodeList<T> Neighbors 25 { 26 get 27 { 28 return neighbors; 29 } 30 set 31 { 32 neighbors = value; 33 } 34 } 35}

C#

1using System.Collections.ObjectModel; 2 3public class NodeList<T> : Collection<Node<T>> 4{ 5 public NodeList() : base() { } 6 public NodeList(int initialSize) 7 { 8 for (int i = 0; i < initialSize; i++) 9 base.Items.Add(default(Node<T>)); 10 } 11 public Node<T> FindByValue(T value) 12 { 13 foreach (Node<T> node in Items) 14 if (node.Value.Equals(value)) 15 return node; 16 17 return null; 18 } 19}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

認識が誤っていたらご指摘いただきたいのですが、ご質問者さんのおっしゃるドロネーグラフというのは、三角形にドロネー点を追加して分割したり、あるいはエッジフリップで三角形ペアを組み替えたりして新しい三角形が生成された際にそれらをグラフに追加していく、いわば三角形集合の操作履歴みたいなものを指すのでしょうか。
そしてドロネー分割が終わった後でグラフの末端に位置する三角形をかき集めると、それがドロネー分割結果になっている...といったプランでしょうか。

でしたら、別途用意しておくノードコレクションを「全ノードを格納するリスト」ではなく「現在生きているノードのコレクション」としてやるのはどうでしょう。
三角形が分割されたり組み替えられたタイミングでコレクションから古い三角形を削除し、新しい三角形を追加してやることにすれば、コレクション内には常にすべての末端ノードが収集された状態にできるだろうと思います。

ノードが重複することはないでしょうし、ノードの順序づけも不要でしょうから、コレクションとしてはおそらくHashSetがうってつけのような気がします。リファレンスによればAddRemoveも計算コストはO(1)だそうですので、効率面でも有利じゃないかと思いますが、いかがでしょうかね?

投稿2020/12/11 10:33

Bongo

総合スコア10811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KEEL

2020/12/11 12:34 編集

ありがとうございます その認識で恐らく正しいかと...幾何学に詳しいわけではないので断言できず申し訳ないです。 非常に参考になりました。HashSetでの実装もできたのでベストアンサーとさせて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問