コード例 #1
0
        /// <summary>
        /// Sets the spatial partition. (For use by the content pipeline only.)
        /// </summary>
        /// <param name="partition">The spatial partition.</param>
        /// <remarks>
        /// This method is used internally to directly set the spatial partition. The spatial partition
        /// might already be initialized and should not be invalidated.
        /// </remarks>
        internal void SetPartition(ISpatialPartition <int> partition)
        {
            if (partition != null)
            {
                _partition = partition;
                _partition.GetAabbForItem = i => Children[i].Aabb;

                // ----- Validate spatial partition.
                // Some spatial partitions, such as the CompressedAabbTree, are pre-initialized when
                // loaded via content pipeline. Other spatial partitions need to be initialized manually.
                int numberOfChildren = Children.Count;
                if (_partition.Count != numberOfChildren)
                {
                    // The partition is not initialized.
                    _partition.Clear();
                    for (int i = 0; i < numberOfChildren; i++)
                    {
                        _partition.Add(i);
                    }

                    _partition.Update(false);
                }
                else
                {
                    // The partition is already initialized.
                    Debug.Assert(Enumerable.Range(0, numberOfChildren).All(_partition.Contains), "Invalid partition. The pre-initialized partition does not contain the same children as the CompositeShape.");
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Called when the <see cref="Children"/> collection was changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="eventArgs">
        /// The <see cref="CollectionChangedEventArgs{IGeometricObject}"/> instance containing the event
        /// data.
        /// </param>
        private void OnChildrenChanged(object sender, CollectionChangedEventArgs <IGeometricObject> eventArgs)
        {
            if (eventArgs.Action == CollectionChangedAction.Move)
            {
                return;
            }

            // Handle removed items.
            var oldItems         = eventArgs.OldItems;
            int numberOfOldItems = oldItems.Count;

            for (int i = 0; i < numberOfOldItems; i++)
            {
                var geometricObject = oldItems[i];

                geometricObject.PoseChanged  -= OnChildShapeChanged;
                geometricObject.ShapeChanged -= OnChildShapeChanged;
            }

            // Handle new items.
            var newItems         = eventArgs.NewItems;
            int numberOfNewItems = newItems.Count;

            for (int i = 0; i < numberOfNewItems; i++)
            {
                var geometricObject = newItems[i];

                geometricObject.PoseChanged  += OnChildShapeChanged;
                geometricObject.ShapeChanged += OnChildShapeChanged;
            }

            // Rebuild spatial partition.
            if (_partition != null)
            {
                _partition.Clear();
                int numberOfChildren = Children.Count;
                for (int i = 0; i < numberOfChildren; i++)
                {
                    _partition.Add(i);
                }
            }

            if (numberOfOldItems == 1 &&
                numberOfNewItems == 1 &&
                eventArgs.OldItemsIndex == eventArgs.NewItemsIndex)
            {
                // Exactly one item was replaced.
                // --> Set the feature index of the item in the event args.
                var shapeChangedEventArgs = ShapeChangedEventArgs.Create(eventArgs.OldItemsIndex);
                OnChanged(shapeChangedEventArgs);
                shapeChangedEventArgs.Recycle();
            }
            else
            {
                // Multiple items added or removed. The indices of multiple items have changed.
                // --> Do not set a feature index. Use the default.
                OnChanged(ShapeChangedEventArgs.Empty);
            }
        }
コード例 #3
0
        public SpatialPartitionSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.Gray;
            GraphicsScreen.DrawReticle     = true;
            SetCamera(new Vector3(0, 1, 10), 0, 0);

            // Create a spatial partition. DigitalRune Geometry supports several types, see also
            // http://digitalrune.github.io/DigitalRune-Documentation/html/e32cab3b-cc7c-42ee-8ec9-23dd4467edd0.htm#WhichPartition
            // An AabbTree is useful for static objects. A DynamicAabbTree is good for moving objects.
            // The spatial partition can manage different types of items. In this case it manages
            // GeometricObjects. A delegate has to inform the spatial partition how to get the AABB
            // of an object.
            //_spatialPartition = new DynamicAabbTree<GeometricObject>
            _spatialPartition = new AabbTree <GeometricObject>
            {
                GetAabbForItem = geometricObject => geometricObject.Aabb,

                // Optional: The tree is automatically built using a mixed top-down/bottom-up approach.
                // Bottom-up building is slower but produces better trees. If the tree building takes too
                // long, we can lower the BottomUpBuildThreshold (default is 128).
                //BottomUpBuildThreshold = 0,

                // Optional: A filter can be set to disable certain kind of overlaps.
                //Filter = ...
            };

            // Create a triangle mesh.
            var triangleMesh      = new SphereShape(1).GetMesh(0.01f, 4);
            var triangleMeshShape = new TriangleMeshShape(triangleMesh)
            {
                // TriangleMeshShapes can also use a spatial partition to manage triangle.
                // The items in the spatial partition are the triangle indices. The GetAabbForItem
                // delegate is set automatically.
                Partition = new AabbTree <int>(),
            };

            // Spatial partitions are built automatically when needed. However, it is still recommended
            // to call Update to initialize the spatial partition explicitly.
            triangleMeshShape.Partition.Update(false);

            // Add a lot of triangle mesh objects to _spatialPartition.
            var random = new Random();

            for (int i = 0; i < 50; i++)
            {
                var randomPosition  = new Vector3(random.NextFloat(-6, 6), random.NextFloat(-3, 3), random.NextFloat(-10, 0));
                var geometricObject = new GeometricObject(triangleMeshShape, new Pose(randomPosition));
                _spatialPartition.Add(geometricObject);
            }

            _spatialPartition.Update(false);
        }
コード例 #4
0
        /// <summary>
        /// Invalidates the whole triangle mesh or a single triangle.
        /// </summary>
        /// <param name="triangleIndex">
        /// Index of the triangle. Can be -1 to invalidate the whole mesh.
        /// </param>
        /// <param name="invalidateTopology">
        /// If set to <see langword="true"/> the mesh topology is invalidated.
        /// </param>
        /// <remarks>
        /// <para>
        /// This method must be called if the position of a triangle stored in <see cref="Mesh"/> is
        /// changed. This method updates the <see cref="Partition"/> and raises the
        /// <see cref="Shape.Changed"/> event by calling <see cref="Shape.OnChanged"/>.
        /// </para>
        /// <para>
        /// If the mesh topology has changed, <paramref name="invalidateTopology"/> must be set to
        /// <see langword="true"/>. The topology has changed if triangle neighbor relationships have
        /// changed. If each triangle has the same neighbor triangles as before and only the vertices
        /// were moved, <paramref name="invalidateTopology"/> can be <see langword="false"/>.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="triangleIndex"/> is out of range.
        /// </exception>
        public void Invalidate(int triangleIndex, bool invalidateTopology)
        {
            int numberOfTriangles = Mesh.NumberOfTriangles;

            if (triangleIndex >= numberOfTriangles)
            {
                throw new ArgumentOutOfRangeException("triangleIndex");
            }

            // Set cached AABB to "invalid".
            _aabbLocal = new Aabb(new Vector3(float.NaN), new Vector3(float.NaN));

            // Fill new spatial partition.
            if (_partition != null)
            {
                if (numberOfTriangles != _partition.Count)
                {
                    // Triangle count has changed. Re-initialize partition content.
                    _partition.Clear();
                    for (int i = 0; i < numberOfTriangles; i++)
                    {
                        _partition.Add(i);
                    }
                }
                else
                {
                    // Same number of triangles - invalidate the triangle.
                    if (triangleIndex >= 0)
                    {
                        _partition.Invalidate(triangleIndex);
                    }
                    else
                    {
                        _partition.Invalidate();
                    }
                }
            }

            if (invalidateTopology)
            {
                ComputeTriangleNeighbors();
            }

            if (triangleIndex < 0)
            {
                OnChanged(ShapeChangedEventArgs.Empty);
            }
            else
            {
                var eventArgs = ShapeChangedEventArgs.Create(triangleIndex);
                OnChanged(eventArgs);
                eventArgs.Recycle();
            }
        }
コード例 #5
0
    public SpatialPartitionSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.Gray;
      GraphicsScreen.DrawReticle = true;
      SetCamera(new Vector3F(0, 1, 10), 0, 0);

      // Create a spatial partition. DigitalRune Geometry supports several types, see also
      // http://digitalrune.github.io/DigitalRune-Documentation/html/e32cab3b-cc7c-42ee-8ec9-23dd4467edd0.htm#WhichPartition
      // An AabbTree is useful for static objects. A DynamicAabbTree is good for moving objects.
      // The spatial partition can manage different types of items. In this case it manages
      // GeometricObjects. A delegate has to inform the spatial partition how to get the AABB
      // of an object.
      //_spatialPartition = new DynamicAabbTree<GeometricObject>
      _spatialPartition = new AabbTree<GeometricObject>
      {
        GetAabbForItem = geometricObject => geometricObject.Aabb,

        // Optional: The tree is automatically built using a mixed top-down/bottom-up approach. 
        // Bottom-up building is slower but produces better trees. If the tree building takes too 
        // long, we can lower the BottomUpBuildThreshold (default is 128).
        //BottomUpBuildThreshold = 0,

        // Optional: A filter can be set to disable certain kind of overlaps.
        //Filter = ...
      };

      // Create a triangle mesh.
      var triangleMesh = new SphereShape(1).GetMesh(0.01f, 4);
      var triangleMeshShape = new TriangleMeshShape(triangleMesh)
      {
        // TriangleMeshShapes can also use a spatial partition to manage triangle.
        // The items in the spatial partition are the triangle indices. The GetAabbForItem
        // delegate is set automatically.
        Partition = new AabbTree<int>(),
      };

      // Spatial partitions are built automatically when needed. However, it is still recommended
      // to call Update to initialize the spatial partition explicitly.
      triangleMeshShape.Partition.Update(false);

      // Add a lot of triangle mesh objects to _spatialPartition.
      var random = new Random();
      for (int i = 0; i < 50; i++)
      {
        var randomPosition = new Vector3F(random.NextFloat(-6, 6), random.NextFloat(-3, 3), random.NextFloat(-10, 0));
        var geometricObject = new GeometricObject(triangleMeshShape, new Pose(randomPosition));
        _spatialPartition.Add(geometricObject);
      }

      _spatialPartition.Update(false);
    }
コード例 #6
0
        public void SetUp()
        {
            RandomHelper.Random = new Random(1234567);

            _testObjects.Clear();
            _testObjectsOfPartition2.Clear();

            TestObject.NextId = 0;
            _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));
            _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));
            _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));
            _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));

            _partition2 = new AabbTree <int>();
            _partition2.GetAabbForItem = GetAabbOfTestObjectOfPartition2;
            _partition2.Add(0);
            _partition2.Add(1);
            _partition2.Add(2);
            _partition2.Add(3);

            _conservativeAabb     = false;
            _conservativeOverlaps = false;
        }
コード例 #7
0
        public void SetUp()
        {
            RandomHelper.Random = new Random(1234567);

              _testObjects.Clear();
              _testObjectsOfPartition2.Clear();

              TestObject.NextId = 0;
              _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));
              _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));
              _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));
              _testObjectsOfPartition2.Add(new TestObject(GetRandomAabb()));

              _partition2 = new AabbTree<int>();
              _partition2.GetAabbForItem = GetAabbOfTestObjectOfPartition2;
              _partition2.Add(0);
              _partition2.Add(1);
              _partition2.Add(2);
              _partition2.Add(3);

              _conservativeAabb = false;
              _conservativeOverlaps = false;
        }
コード例 #8
0
        private void TestPartition(ISpatialPartition <int> partition)
        {
            partition.Clear();
            Assert.AreEqual(0, partition.Count);

            partition.EnableSelfOverlaps = true;
            Assert.AreEqual(0, partition.GetOverlaps().Count());
            Assert.AreEqual(0, partition.GetOverlaps(0).Count());
            Assert.AreEqual(0, partition.GetOverlaps(new Aabb()).Count());
            Assert.AreEqual(0, partition.GetOverlaps(_partition2).Count());
            Assert.AreEqual(0, partition.GetOverlaps(Vector3.One, Pose.Identity, _partition2, Vector3.One, Pose.Identity).Count());


            var testObject = new TestObject(new Aabb(new Vector3(10), new Vector3(10)));

            _testObjects.Add(testObject);
            partition.Add(testObject.Id);

            for (int i = 0; i < 1000; i++)
            {
                // ----- Tests
                Assert.AreEqual(_testObjects.Count, partition.Count, "Wrong number of items.");

                if (i > 10 && i % 6 == 0)
                {
                    TestGetOverlaps0(partition);
                }
                if (i > 10 && i % 6 == 1)
                {
                    TestGetOverlaps1(partition);
                }
                if (i > 10 && i % 6 == 2)
                {
                    TestGetOverlaps2(partition);
                }
                if (i > 10 && i % 6 == 3)
                {
                    TestGetOverlaps3(partition);
                }
                if (i > 10 && i % 6 == 4)
                {
                    TestGetOverlaps4(partition);
                }
                if (i > 10 && i % 6 == 5)
                {
                    TestGetOverlaps5(partition);
                }

                // Update partition. From time to time rebuild all.
                // For the above tests update should have been called automatically!
                partition.Update(i % 10 == 9);
                TestAabb(partition);

                var dice100 = RandomHelper.Random.Next(0, 100);
                if (dice100 < 2)
                {
                    // Test remove/re-add without Update inbetween.
                    if (partition.Count > 0)
                    {
                        partition.Remove(_testObjects[0].Id);
                        partition.Add(_testObjects[0].Id);
                    }
                }


                dice100 = RandomHelper.Random.Next(0, 100);
                if (dice100 < 10)
                {
                    // Remove objects.
                    int removeCount = RandomHelper.Random.NextInteger(1, 4);
                    for (int k = 0; k < removeCount && partition.Count > 0; k++)
                    {
                        var index = RandomHelper.Random.NextInteger(0, partition.Count - 1);
                        var obj   = _testObjects[index];
                        _testObjects.Remove(obj);
                        partition.Remove(obj.Id);
                    }
                }

                dice100 = RandomHelper.Random.Next(0, 100);
                if (dice100 < 10)
                {
                    // Add new objects.
                    int addCount = RandomHelper.Random.NextInteger(1, 4);
                    for (int k = 0; k < addCount; k++)
                    {
                        var newObj = new TestObject(GetRandomAabb());
                        _testObjects.Add(newObj);
                        partition.Add(newObj.Id);
                    }
                }
                else
                {
                    // Move an object.
                    int moveCount = RandomHelper.Random.NextInteger(1, 10);
                    for (int k = 0; k < moveCount && partition.Count > 0; k++)
                    {
                        var index = RandomHelper.Random.NextInteger(0, partition.Count - 1);
                        var obj   = _testObjects[index];
                        obj.Aabb = GetRandomAabb();
                        partition.Invalidate(obj.Id);
                    }
                }

                // From time to time invalidate all.
                if (dice100 < 3)
                {
                    partition.Invalidate();
                }

                // From time to time change EnableSelfOverlaps.
                if (dice100 > 3 && dice100 < 6)
                {
                    partition.EnableSelfOverlaps = false;
                }
                else if (dice100 < 10)
                {
                    partition.EnableSelfOverlaps = true;
                }

                // From time to time change filter.
                if (dice100 > 10 && dice100 < 13)
                {
                    partition.Filter = null;
                }
                else if (dice100 < 10)
                {
                    if (partition.Filter == null)
                    {
                        partition.Filter = new DelegatePairFilter <int>(AreInSameGroup);
                    }
                }
            }

            partition.Clear();
            Assert.AreEqual(0, partition.Count);
        }
コード例 #9
0
ファイル: CompositeShape.cs プロジェクト: Zolniu/DigitalRune
    //--------------------------------------------------------------
    #region Methods
    //--------------------------------------------------------------

#if XNA || MONOGAME
    /// <summary>
    /// Sets the spatial partition. (For use by the content pipeline only.)
    /// </summary>
    /// <param name="partition">The spatial partition.</param>
    /// <remarks>
    /// This method is used internally to directly set the spatial partition. The spatial partition
    /// might already be initialized and should not be invalidated.
    /// </remarks>
    internal void SetPartition(ISpatialPartition<int> partition)
    {
      if (partition != null)
      {
        _partition = partition;
        _partition.GetAabbForItem = i => Children[i].Aabb;

        // ----- Validate spatial partition.
        // Some spatial partitions, such as the CompressedAabbTree, are pre-initialized when 
        // loaded via content pipeline. Other spatial partitions need to be initialized manually.
        int numberOfChildren = Children.Count;
        if (_partition.Count != numberOfChildren)
        {
          // The partition is not initialized.
          _partition.Clear();
          for (int i = 0; i < numberOfChildren; i++)
            _partition.Add(i);

          _partition.Update(false);
        }
        else
        {
          // The partition is already initialized.
          Debug.Assert(Enumerable.Range(0, numberOfChildren).All(_partition.Contains), "Invalid partition. The pre-initialized partition does not contain the same children as the CompositeShape.");
        }
      }
    }
コード例 #10
0
        private void TestPartition(ISpatialPartition<int> partition)
        {
            partition.Clear();
              Assert.AreEqual(0, partition.Count);

              partition.EnableSelfOverlaps = true;
              Assert.AreEqual(0, partition.GetOverlaps().Count());
              Assert.AreEqual(0, partition.GetOverlaps(0).Count());
              Assert.AreEqual(0, partition.GetOverlaps(new Aabb()).Count());
              Assert.AreEqual(0, partition.GetOverlaps(_partition2).Count());
              Assert.AreEqual(0, partition.GetOverlaps(Vector3F.One, Pose.Identity, _partition2, Vector3F.One, Pose.Identity).Count());

              var testObject = new TestObject(new Aabb(new Vector3F(10), new Vector3F(10)));
              _testObjects.Add(testObject);
              partition.Add(testObject.Id);

              for (int i = 0; i < 1000; i++)
              {
            // ----- Tests
            Assert.AreEqual(_testObjects.Count, partition.Count, "Wrong number of items.");

            if (i > 10 && i % 6 == 0)
              TestGetOverlaps0(partition);
            if (i > 10 && i % 6 == 1)
              TestGetOverlaps1(partition);
            if (i > 10 && i % 6 == 2)
              TestGetOverlaps2(partition);
            if (i > 10 && i % 6 == 3)
              TestGetOverlaps3(partition);
            if (i > 10 && i % 6 == 4)
              TestGetOverlaps4(partition);
            if (i > 10 && i % 6 == 5)
              TestGetOverlaps5(partition);

            // Update partition. From time to time rebuild all.
            // For the above tests update should have been called automatically!
            partition.Update(i % 10 == 9);
            TestAabb(partition);

            var dice100 = RandomHelper.Random.Next(0, 100);
            if (dice100 < 2)
            {
              // Test remove/re-add without Update inbetween.
              if (partition.Count > 0)
              {
            partition.Remove(_testObjects[0].Id);
            partition.Add(_testObjects[0].Id);
              }
            }

            dice100 = RandomHelper.Random.Next(0, 100);
            if (dice100 < 10)
            {
              // Remove objects.
              int removeCount = RandomHelper.Random.NextInteger(1, 4);
              for (int k = 0; k < removeCount && partition.Count > 0; k++)
              {
            var index = RandomHelper.Random.NextInteger(0, partition.Count - 1);
            var obj = _testObjects[index];
            _testObjects.Remove(obj);
            partition.Remove(obj.Id);
              }
            }

            dice100 = RandomHelper.Random.Next(0, 100);
            if (dice100 < 10)
            {
              // Add new objects.
              int addCount = RandomHelper.Random.NextInteger(1, 4);
              for (int k = 0; k < addCount; k++)
              {
            var newObj = new TestObject(GetRandomAabb());
            _testObjects.Add(newObj);
            partition.Add(newObj.Id);
              }
            }
            else
            {
              // Move an object.
              int moveCount = RandomHelper.Random.NextInteger(1, 10);
              for (int k = 0; k < moveCount && partition.Count > 0; k++)
              {
            var index = RandomHelper.Random.NextInteger(0, partition.Count - 1);
            var obj = _testObjects[index];
            obj.Aabb = GetRandomAabb();
            partition.Invalidate(obj.Id);
              }
            }

            // From time to time invalidate all.
            if (dice100 < 3)
              partition.Invalidate();

            // From time to time change EnableSelfOverlaps.
            if (dice100 > 3 && dice100 < 6)
              partition.EnableSelfOverlaps = false;
            else if (dice100 < 10)
              partition.EnableSelfOverlaps = true;

            // From time to time change filter.
            if (dice100 > 10 && dice100 < 13)
            {
              partition.Filter = null;
            }
            else if (dice100 < 10)
            {
              if (partition.Filter == null)
            partition.Filter = new DelegatePairFilter<int>(AreInSameGroup);
            }
              }

              partition.Clear();
              Assert.AreEqual(0, partition.Count);
        }