4

ここに投稿するのは初めてですが、私はこのサイトを数年前から読んでいます。C# で単純なジェネリック型オクトリーを実装しようとしています (いくつかの XNA インクルードを使用)。私は徹底的に調査し、概念を理解しましたが、それを機能させることができないようです. 検索すると、他の言語での実装がいくつか見つかりますが、それらはすべて特定のアプリケーションに合わせてカスタム調整されているようです。そして、私はそれらからあまり意味を成すことができませんでした.

以下は、これまでの私の Octree クラスです。Vector3、BoundingBox、および ContainmentType は XNA のものです。最大ポイントと最小ポイント、および境界内にあるポイントのリストをフィードします。ただし、実際にツリーに追加されるポイントはありません。どんな助けでも大歓迎です!

public class Octree<T> : ISerializable
{   
    Vector3 max;
    Vector3 min;
    OctreeNode head;

    public Octree(Vector3 min, Vector3 max, List<Vector3> values)
    {
        this.max = max;
        this.min = min;
        head = new OctreeNode( min, max,  values);           
    }

    public Octree() { }

    public Octree(SerializationInfo info, StreamingContext context)
    {
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {            
    }

    internal class OctreeNode
    {            
        Vector3 max;
        Vector3 min;
        Vector3 center;
        public Vector3 position;
        public T data;

        public BoundingBox nodeBox;
        public List<OctreeNode> subNodes;
        public OctreeNode( Vector3 min, Vector3 max,List<Vector3> coords)
        {
            nodeBox = new BoundingBox(min, max);
            subNodes = new List<OctreeNode>();

            this.min = min;
            this.max = max;
            center = (min + ((max - min) / 2));

            nodeBox = new BoundingBox(min, max);
            if (coords.Count == 0)
            { return; }
            subNodes.Add(new OctreeNode(center, max));
            subNodes.Add(new OctreeNode(new Vector3(min.X, center.Y, center.Z), new Vector3(center.X, max.Y, min.Z)));
            subNodes.Add(new OctreeNode(new Vector3(min.X, center.Y, max.Z), new Vector3(center.X, max.Y, center.Z)));
            subNodes.Add(new OctreeNode(new Vector3(center.X, center.Y, max.Z), new Vector3(max.X, max.Y, center.Z)));

            subNodes.Add(new OctreeNode(new Vector3(center.X, min.Y, center.Z), new Vector3(max.X, center.Y, min.Z)));
            subNodes.Add(new OctreeNode(new Vector3(min.X, min.Y, center.Z), new Vector3(center.X, center.Y, min.Z)));
            subNodes.Add(new OctreeNode(new Vector3(min.X, min.Y, max.Z), center));
            subNodes.Add(new OctreeNode(new Vector3(center.X,min.Y,max.Z), new Vector3(max.X,center.Y,center.Z)));


            List<List<Vector3>> octants = new List<List<Vector3>>();
            for (int i = 0; i < 8; i++)
            {
                octants.Add(new List<Vector3>());
            }
            foreach (Vector3 v in coords)
            {
                int i = 0;
                foreach(OctreeNode n in subNodes)
                {
                    ContainmentType t = n.nodeBox.Contains(v);

                    if (t.Equals(ContainmentType.Contains))
                    {
                        octants[i].Add(v);
                    }
                    i++;
                }
            }

            for (int i=0;i<subNodes.Count;i++)
            {
                if (octants[i].Count > 0)
                {
                    Vector3 v = octants[i][0];
                    octants[i].Remove(v);
                    subNodes[i] = new OctreeNode(subNodes[i].min, subNodes[i].max, octants[i]);
                }
            }
        }

        public OctreeNode(Vector3 min, Vector3 max)
        {
            nodeBox = new BoundingBox(min, max);
        }            
    }
}
4

1 に答える 1

7

コードを Visual Studio の新しいプロジェクトに貼り付けOctree、いくつかのポイント値でコンストラクターを呼び出してデバッグしました。octree を機能させるのに役立ついくつかの簡単な選択を次に示します。

  1. ではOctreeNode(Vector3 min, Vector3 max, List<Vector3> coords)subNodes適切な最小境界と最大境界を持たないものがあります。たとえば、new Vector3(min.X, min.Y, max.Z), centerからmax.Zまでの範囲center.zです。上限は常に下限よりも小さくなります。このようなエラーの可能性を減らすために、次のようにノードを体系的にリストしてみてください。

    subNodes.Add(new OctreeNode(new Vector3(min.X,    min.Y,    min.Z),    new Vector3(center.X, center.Y, center.Z)));
    subNodes.Add(new OctreeNode(new Vector3(min.X,    min.Y,    center.Z), new Vector3(center.X, center.Y, max.Z)));
    subNodes.Add(new OctreeNode(new Vector3(min.X,    center.Y, min.Z),    new Vector3(center.X, max.Y,    center.Z)));
    subNodes.Add(new OctreeNode(new Vector3(min.X,    center.Y, center.Z), new Vector3(center.X, max.Y,    max.Z)));
    subNodes.Add(new OctreeNode(new Vector3(center.X, min.Y,    min.Z),    new Vector3(max.X,    center.Y, center.Z)));
    subNodes.Add(new OctreeNode(new Vector3(center.X, min.Y,    center.Z), new Vector3(max.X,    center.Y, max.Z)));
    subNodes.Add(new OctreeNode(new Vector3(center.X, center.Y, min.Z),    new Vector3(max.X,    max.Y,    center.Z)));
    subNodes.Add(new OctreeNode(new Vector3(center.X, center.Y, center.Z), new Vector3(max.X,    max.Y,    max.Z)));
    
  2. コンストラクターでは、フィールド、、および をOctreeNode(Vector3 min, Vector3 max)初期化しません。その結果、最終的なs の下限と上限が常にライン上でゼロに設定されている場合、minmaxcenterOctreeNode

       subNodes[i] = new OctreeNode(subNodes[i].min, subNodes[i].max, octants[i]);
    
  3. 同じ行で、実際にノードの範囲内にあるポイント以外のすべてのポイントをノード値として渡します。ローカル変数vは、範囲内にある値です。ノード値として渡されoctantsた後に削除されます。octants

  4. コンストラクターに渡された値OctreeNodeは実際にはどこにも保存されませんが、作成されたノードは常に小さなノードに分割され、値はサブノードに渡されます。したがって、上記の 3 つの問題を修正すると、コードが無限再帰になります。再帰を中断するには、停止条件を実装する必要があります。通常、オクツリーでは、ノード内に十分に少数の値がある場合、ノードはサブノードに分割されず、値はノードに格納されます。ノードに十分な数の値が含まれている場合にのみ、ノードが分割され、その値が新しいサブノードに分散されます。

于 2013-03-15T22:27:39.653 に答える