コード例 #1
0
        /// <summary>
        /// Clamps a road path to the terrain height.
        /// </summary>
        /// <param name="road">The path that represents the road.</param>
        /// <param name="terrain">The terrain represented by a <see cref="HeightField"/>.</param>
        /// <remarks>
        /// The y position of each path key is set to the terrain height at the xz position.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="terrain"/> is <see langword="null"/>.
        /// </exception>
        public static void ClampRoadToTerrain(Path3F road, HeightField terrain)
        {
            if (road == null)
            return;
              if (terrain == null)
            throw new ArgumentNullException("terrain");

              foreach (var key in road)
              {
            Vector3F position = key.Point;
            float height = terrain.GetHeight(position.X, position.Z);
            if (!Numeric.IsNaN(height))
            {
              position.Y = height;
              key.Point = position;
            }
              }
        }
コード例 #2
0
        public void Sort()
        {
            Path3F empty = new Path3F();

            empty.Sort();

            Path3F path = CreatePath();

            // Un-sort the keys.
            path[7].Parameter = 13;

            path.Sort();
            Assert.AreEqual(8, path.Count);
            Assert.AreEqual(10, path[0].Parameter);
            Assert.AreEqual(13, path[1].Parameter);
            Assert.AreEqual(15, path[2].Parameter);
            // ...
            Assert.AreEqual(35, path[7].Parameter);
        }
コード例 #3
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void GetLength()
        {
            Path3F empty = new Path3F();
              empty.Sort();
              Assert.AreEqual(0, empty.GetLength(0, 1, 100, 0.0001f));

              Path3F path = CreatePath();
              path.PreLoop = CurveLoopType.Constant;
              path.PostLoop = CurveLoopType.Oscillate;
              Assert.IsTrue(Numeric.AreEqual((new Vector3F(0, 0, 1) - new Vector3F(1, 2, 3)).Length, path.GetLength(-1, 12, 100, 0.0001f), 0.001f));
              Assert.IsTrue(Numeric.AreEqual((new Vector3F(0, 0, 1) - new Vector3F(1, 2, 3)).Length, path.GetLength(-1, 20, 100, 0.0001f), 0.001f));

              CatmullRomSegment3F catmullOscillate = new CatmullRomSegment3F()
              {
            Point1 = new Vector3F(10, 12, 14),
            Point2 = new Vector3F(10, 14, 8),
            Point3 = new Vector3F(20, 14, 8),
            Point4 = new Vector3F(30, 14, 8),
              };
              float desiredLength = catmullOscillate.GetLength(0, 1, 20, 0.0001f);
              float actualLength = path.GetLength(40, 50, 20, 0.0001f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.001f));
              desiredLength = catmullOscillate.GetLength(1, 0.8f, 20, 0.0001f);
              actualLength = path.GetLength(52, 50, 20, 0.0001f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.001f));
              desiredLength = catmullOscillate.GetLength(1, 0.8f, 20, 0.0001f) * 2;
              actualLength = path.GetLength(52, 48, 20, 0.0001f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.001f));

              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Cycle;

              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.CycleOffset;

              path.PreLoop = CurveLoopType.CycleOffset;
              path.PostLoop = CurveLoopType.Linear;

              path.PreLoop = CurveLoopType.Oscillate;
              path.PostLoop = CurveLoopType.Constant;
        }
コード例 #4
0
        /// <summary>
        /// Clamps a road path to the terrain height.
        /// </summary>
        /// <param name="road">The path that represents the road.</param>
        /// <param name="terrain">The terrain represented by a <see cref="HeightField"/>.</param>
        /// <remarks>
        /// The y position of each path key is set to the terrain height at the xz position.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="terrain"/> is <see langword="null"/>.
        /// </exception>
        public static void ClampRoadToTerrain(Path3F road, HeightField terrain)
        {
            if (road == null)
            {
                return;
            }
            if (terrain == null)
            {
                throw new ArgumentNullException("terrain");
            }

            foreach (var key in road)
            {
                Vector3F position = key.Point;
                float    height   = terrain.GetHeight(position.X, position.Z);
                if (!Numeric.IsNaN(height))
                {
                    position.Y = height;
                    key.Point  = position;
                }
            }
        }
コード例 #5
0
        // Add a random path.
        private void CreateRandomPath()
        {
            var path  = new Path3F();
            var point = new Vector3F(0, 0, 0);

            path.Add(new PathKey3F
            {
                Interpolation = SplineInterpolation.CatmullRom,
                Parameter     = 0,
                Point         = point
            });
            for (int i = 1; i < 10; i++)
            {
                point += RandomHelper.Random.NextQuaternionF().Rotate(new Vector3F(0, 0.5f, 0));
                path.Add(new PathKey3F
                {
                    Interpolation = SplineInterpolation.CatmullRom,
                    Parameter     = i,
                    Point         = point
                });
            }
            var pathFigure = new PathFigure3F();

            pathFigure.Segments.Add(path);

            var pathLineNode = new FigureNode(pathFigure)
            {
                Name              = "RandomPath",
                PoseLocal         = new Pose(new Vector3F(4, 1, 2)),
                StrokeThickness   = 3,
                StrokeColor       = new Vector3F(0.5f, 0.3f, 1),
                StrokeAlpha       = 1f,
                DashInWorldSpace  = true,
                StrokeDashPattern = new Vector4F(10, 1, 1, 1) / 100,
            };

            _scene.Children.Add(pathLineNode);
        }
コード例 #6
0
        public void GetKey()
        {
            Path3F empty = new Path3F();

            empty.Sort();
            Assert.AreEqual(-1, empty.GetKeyIndex(20));

            Path3F path = CreatePath();

            path.PreLoop  = CurveLoopType.Constant;
            path.PostLoop = CurveLoopType.Oscillate;
            Assert.AreEqual(0, path.GetKeyIndex(-28));
            Assert.AreEqual(0, path.GetKeyIndex(3));
            Assert.AreEqual(0, path.GetKeyIndex(10));
            Assert.AreEqual(3, path.GetKeyIndex(20));
            Assert.AreEqual(4, path.GetKeyIndex(28));
            Assert.AreEqual(7, path.GetKeyIndex(40));
            Assert.AreEqual(6, path.GetKeyIndex(42));
            Assert.AreEqual(2, path.GetKeyIndex(78));

            path.PreLoop  = CurveLoopType.Linear;
            path.PostLoop = CurveLoopType.Cycle;
            Assert.AreEqual(-1, path.GetKeyIndex(-28));
            Assert.AreEqual(-1, path.GetKeyIndex(3));
            Assert.AreEqual(0, path.GetKeyIndex(10));
            Assert.AreEqual(3, path.GetKeyIndex(20));
            Assert.AreEqual(4, path.GetKeyIndex(28));
            Assert.AreEqual(7, path.GetKeyIndex(40));
            Assert.AreEqual(0, path.GetKeyIndex(42));
            Assert.AreEqual(2, path.GetKeyIndex(78));

            path.PreLoop  = CurveLoopType.Cycle;
            path.PostLoop = CurveLoopType.CycleOffset;
            Assert.AreEqual(5, path.GetKeyIndex(-28));
            Assert.AreEqual(5, path.GetKeyIndex(3));
            Assert.AreEqual(0, path.GetKeyIndex(10));
            Assert.AreEqual(3, path.GetKeyIndex(20));
            Assert.AreEqual(4, path.GetKeyIndex(28));
            Assert.AreEqual(7, path.GetKeyIndex(40));
            Assert.AreEqual(0, path.GetKeyIndex(42));
            Assert.AreEqual(2, path.GetKeyIndex(78));

            path.PreLoop  = CurveLoopType.CycleOffset;
            path.PostLoop = CurveLoopType.Linear;
            Assert.AreEqual(5, path.GetKeyIndex(-28));
            Assert.AreEqual(5, path.GetKeyIndex(3));
            Assert.AreEqual(0, path.GetKeyIndex(10));
            Assert.AreEqual(3, path.GetKeyIndex(20));
            Assert.AreEqual(4, path.GetKeyIndex(28));
            Assert.AreEqual(7, path.GetKeyIndex(40));
            Assert.AreEqual(7, path.GetKeyIndex(42));
            Assert.AreEqual(7, path.GetKeyIndex(78));

            path.PreLoop  = CurveLoopType.Oscillate;
            path.PostLoop = CurveLoopType.Constant;
            Assert.AreEqual(5, path.GetKeyIndex(-28));
            Assert.AreEqual(1, path.GetKeyIndex(3));
            Assert.AreEqual(0, path.GetKeyIndex(10));
            Assert.AreEqual(3, path.GetKeyIndex(20));
            Assert.AreEqual(4, path.GetKeyIndex(28));
            Assert.AreEqual(7, path.GetKeyIndex(40));
            Assert.AreEqual(7, path.GetKeyIndex(42));
            Assert.AreEqual(7, path.GetKeyIndex(78));
        }
コード例 #7
0
        private void CreatePath()
        {
            // Create a cyclic path. (More information on paths can be found in the DigitalRune
            // Mathematics documentation and related samples.)
            _path = new Path3F
            {
                SmoothEnds = true,
                PreLoop    = CurveLoopType.Cycle,
                PostLoop   = CurveLoopType.Cycle
            };

            // The curvature of the path is defined by a number of path keys.
            _path.Add(new PathKey3F
            {
                Parameter     = 0,                              // The path parameter defines position of the path key on the curve.
                Point         = new Vector3(-4, 0.5f, -3),      // The world space position of the path key.
                Interpolation = SplineInterpolation.CatmullRom, // The type of interpolation that is used between this path key and the next.
            });
            _path.Add(new PathKey3F
            {
                Parameter     = 1,
                Point         = new Vector3(-1, 0.5f, -5),
                Interpolation = SplineInterpolation.CatmullRom,
            });
            _path.Add(new PathKey3F
            {
                Parameter     = 2,
                Point         = new Vector3(3, 0.5f, -4),
                Interpolation = SplineInterpolation.CatmullRom,
            });
            _path.Add(new PathKey3F
            {
                Parameter     = 3,
                Point         = new Vector3(0, 0.5f, 0),
                Interpolation = SplineInterpolation.CatmullRom,
            });
            _path.Add(new PathKey3F
            {
                Parameter     = 4,
                Point         = new Vector3(-3, 0.5f, 3),
                Interpolation = SplineInterpolation.CatmullRom,
            });
            _path.Add(new PathKey3F
            {
                Parameter     = 5,
                Point         = new Vector3(-1, 0.5f, 5),
                Interpolation = SplineInterpolation.CatmullRom,
            });
            _path.Add(new PathKey3F
            {
                Parameter     = 6,
                Point         = new Vector3(0, 0.5f, 0),
                Interpolation = SplineInterpolation.CatmullRom,
            });

            // The last key uses the same position as the first key to create a closed path.
            PathKey3F lastKey = new PathKey3F
            {
                Parameter     = _path.Count,
                Point         = _path[0].Point,
                Interpolation = SplineInterpolation.CatmullRom,
            };

            _path.Add(lastKey);

            // The current path parameter goes from 0 to 7. This path parameter is not linearly
            // proportional to the path length. This is not suitable for animations.
            // To move an object with constant speed along a path, the path parameter should
            // be linearly proportional to the length of the path.
            // ParameterizeByLength() changes the path parameter so that the path parameter
            // at the each key is equal to the length of path (measured from the first key position
            // to the current key position).
            // ParameterizeByLength() uses an iterative process, we end the process after 10
            // iterations or when the error is less than 0.01f.
            _path.ParameterizeByLength(10, 0.01f);

            // Sample the path for rendering.
            int   numberOfSamples = _pointList.Length - 1;
            float pathLength      = _path.Last().Parameter;

            for (int i = 0; i <= numberOfSamples; i++)
            {
                Vector3 pointOnPath = _path.GetPoint(pathLength / numberOfSamples * i);
                _pointList[i] = pointOnPath;
            }
        }
コード例 #8
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void SerializationXml()
        {
            PathKey3F pathKey1 = new PathKey3F
              {
            Interpolation = SplineInterpolation.Bezier,
            Parameter = 56.7f,
            Point = new Vector3F(1.2f, 3.4f, 5.6f),
            TangentIn = new Vector3F(0.7f, 2.6f, 5.1f),
            TangentOut = new Vector3F(1.9f, 3.3f, 5.9f)
              };
              PathKey3F pathKey2 = new PathKey3F
              {
            Interpolation = SplineInterpolation.Hermite,
            Parameter = 66.7f,
            Point = new Vector3F(2.2f, 1.4f, 6.6f),
            TangentIn = new Vector3F(1.7f, 3.6f, 4.1f),
            TangentOut = new Vector3F(2.9f, 2.3f, 6.9f)
              };
              Path3F path = new Path3F { pathKey1, pathKey2 };
              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.CycleOffset;
              path.SmoothEnds = true;

              const string fileName = "SerializationPath3F.xml";

              if (File.Exists(fileName))
            File.Delete(fileName);

              XmlSerializer serializer = new XmlSerializer(typeof(Path3F));
              StreamWriter writer = new StreamWriter(fileName);
              serializer.Serialize(writer, path);
              writer.Close();

              serializer = new XmlSerializer(typeof(Path3F));
              FileStream fileStream = new FileStream(fileName, FileMode.Open);
              path = (Path3F)serializer.Deserialize(fileStream);

              Assert.AreEqual(2, path.Count);
              MathAssert.AreEqual(pathKey1, path[0]);
              MathAssert.AreEqual(pathKey2, path[1]);
              Assert.AreEqual(CurveLoopType.Cycle, path.PreLoop);
              Assert.AreEqual(CurveLoopType.CycleOffset, path.PostLoop);
              Assert.AreEqual(true, path.SmoothEnds);
        }
コード例 #9
0
        public void Sort()
        {
            Path3F empty = new Path3F();
              empty.Sort();

              Path3F path = CreatePath();

              // Un-sort the keys.
              path[7].Parameter = 13;

              path.Sort();
              Assert.AreEqual(8, path.Count);
              Assert.AreEqual(10, path[0].Parameter);
              Assert.AreEqual(13, path[1].Parameter);
              Assert.AreEqual(15, path[2].Parameter);
              // ...
              Assert.AreEqual(35, path[7].Parameter);
        }
コード例 #10
0
        public void GetKey()
        {
            Path3F empty = new Path3F();
              empty.Sort();
              Assert.AreEqual(-1, empty.GetKeyIndex(20));

              Path3F path = CreatePath();
              path.PreLoop = CurveLoopType.Constant;
              path.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(0, path.GetKeyIndex(-28));
              Assert.AreEqual(0, path.GetKeyIndex(3));
              Assert.AreEqual(0, path.GetKeyIndex(10));
              Assert.AreEqual(3, path.GetKeyIndex(20));
              Assert.AreEqual(4, path.GetKeyIndex(28));
              Assert.AreEqual(7, path.GetKeyIndex(40));
              Assert.AreEqual(6, path.GetKeyIndex(42));
              Assert.AreEqual(2, path.GetKeyIndex(78));

              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(-1, path.GetKeyIndex(-28));
              Assert.AreEqual(-1, path.GetKeyIndex(3));
              Assert.AreEqual(0, path.GetKeyIndex(10));
              Assert.AreEqual(3, path.GetKeyIndex(20));
              Assert.AreEqual(4, path.GetKeyIndex(28));
              Assert.AreEqual(7, path.GetKeyIndex(40));
              Assert.AreEqual(0, path.GetKeyIndex(42));
              Assert.AreEqual(2, path.GetKeyIndex(78));

              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(5, path.GetKeyIndex(-28));
              Assert.AreEqual(5, path.GetKeyIndex(3));
              Assert.AreEqual(0, path.GetKeyIndex(10));
              Assert.AreEqual(3, path.GetKeyIndex(20));
              Assert.AreEqual(4, path.GetKeyIndex(28));
              Assert.AreEqual(7, path.GetKeyIndex(40));
              Assert.AreEqual(0, path.GetKeyIndex(42));
              Assert.AreEqual(2, path.GetKeyIndex(78));

              path.PreLoop = CurveLoopType.CycleOffset;
              path.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(5, path.GetKeyIndex(-28));
              Assert.AreEqual(5, path.GetKeyIndex(3));
              Assert.AreEqual(0, path.GetKeyIndex(10));
              Assert.AreEqual(3, path.GetKeyIndex(20));
              Assert.AreEqual(4, path.GetKeyIndex(28));
              Assert.AreEqual(7, path.GetKeyIndex(40));
              Assert.AreEqual(7, path.GetKeyIndex(42));
              Assert.AreEqual(7, path.GetKeyIndex(78));

              path.PreLoop = CurveLoopType.Oscillate;
              path.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(5, path.GetKeyIndex(-28));
              Assert.AreEqual(1, path.GetKeyIndex(3));
              Assert.AreEqual(0, path.GetKeyIndex(10));
              Assert.AreEqual(3, path.GetKeyIndex(20));
              Assert.AreEqual(4, path.GetKeyIndex(28));
              Assert.AreEqual(7, path.GetKeyIndex(40));
              Assert.AreEqual(7, path.GetKeyIndex(42));
              Assert.AreEqual(7, path.GetKeyIndex(78));
        }
コード例 #11
0
    private void CreateRoad()
    {
      //RandomHelper.Random = new Random(1234567);

      // Set isClosed to true join the start and the end of the road.
      bool isClosed = false;

      // Create a new TerrainRoadLayer which paints a road onto the terrain.
      // The road itself is defined by a mesh which is set later.
      _roadLayer = new TerrainRoadLayer(GraphicsService)
      {
        DiffuseColor = new Vector3F(0.5f),
        SpecularColor = new Vector3F(1),
        DiffuseTexture = ContentManager.Load<Texture2D>("Terrain/Road-Asphalt-Diffuse"),
        NormalTexture = ContentManager.Load<Texture2D>("Terrain/Road-Asphalt-Normal"),
        SpecularTexture = ContentManager.Load<Texture2D>("Terrain/Road-Asphalt-Specular"),
        HeightTexture = ContentManager.Load<Texture2D>("Terrain/Road-Asphalt-Height"),

        // The size of the tileable detail textures in world space units.
        TileSize = 5,

        // The border blend range controls how the border of the road fades out.
        // We fade out 5% of the texture on each side of the road.
        BorderBlendRange = new Vector4F(0.05f, 0.05f, 0.05f, 0.05f),
      };

      // Create 3D spline path with some semi-random control points.
      _roadPath = new Path3F
      {
        PreLoop = isClosed ? CurveLoopType.Cycle : CurveLoopType.Linear,
        PostLoop = isClosed ? CurveLoopType.Cycle : CurveLoopType.Linear,
        SmoothEnds = isClosed,
      };

      // The position of the next path key.
      Vector3F position = new Vector3F(
        RandomHelper.Random.NextFloat(-20, 20),
        0,
        RandomHelper.Random.NextFloat(-20, 20));

      // The direction to the next path key.
      Vector3F direction = QuaternionF.CreateRotationY(RandomHelper.Random.NextFloat(0, 10)).Rotate(Vector3F.Forward);

      // Add path keys.
      for (int j = 0; j < 10; j++)
      {
        // Instead of a normal PathKey3F, we use a TerrainRoadPathKey which allows to control
        // the road with and the side falloff.
        var key = new TerrainRoadPathKey
        {
          Interpolation = SplineInterpolation.CatmullRom,
          Parameter = j,
          Point = position,

          // The width of the road at the path key.
          Width = RandomHelper.Random.NextFloat(6, 10),

          // The side falloff (which is used in ClampTerrainToRoad to blend the height values with
          // the road).
          SideFalloff = RandomHelper.Random.NextFloat(20, 40),
        };

        _roadPath.Add(key);

        // Get next random position and direction.
        position += direction * RandomHelper.Random.NextFloat(20, 40);
        position.Y += RandomHelper.Random.NextFloat(-2, 2);
        direction = QuaternionF.CreateRotationY(RandomHelper.Random.NextFloat(-1, 1))
                               .Rotate(direction);
      }

      if (isClosed)
      {
        // To create a closed path the first and the last key should be identical.
        _roadPath[_roadPath.Count - 1].Point = _roadPath[0].Point;
        ((TerrainRoadPathKey)_roadPath[_roadPath.Count - 1]).Width = ((TerrainRoadPathKey)_roadPath[0]).Width;
        ((TerrainRoadPathKey)_roadPath[_roadPath.Count - 1]).SideFalloff =
          ((TerrainRoadPathKey)_roadPath[0]).SideFalloff;

        // Since the path is closed we do not have to fade out the start and the end of the road.
        _roadLayer.BorderBlendRange *= new Vector4F(1, 0, 1, 0);
      }

      // Convert the path to a mesh.
      Submesh roadSubmesh;
      Aabb roadAabb;
      float roadLength;
      TerrainRoadLayer.CreateMesh(
        GraphicsService.GraphicsDevice,
        _roadPath,
        4,
        10,
        0.1f,
        out roadSubmesh,
        out roadAabb,
        out roadLength);

      // Set the mesh in the road layer.
      _roadLayer.SetMesh(roadSubmesh, roadAabb, roadLength, true);

      if (isClosed)
      {
        // When the path is closed, the end texture and the start texture coordinates should 
        // match. This is the case if (roadLength / tileSize) is an integer.
        var numberOfTiles = (int)(roadLength / _roadLayer.TileSize);
        _roadLayer.TileSize = roadLength / numberOfTiles;
      }

      // The road layer is added to the layers of a tile. We have to add the road to each terrain
      // tile which it overlaps.
      foreach (var tile in _terrainObject.TerrainNode.Terrain.Tiles)
        if (GeometryHelper.HaveContact(tile.Aabb, _roadLayer.Aabb.Value))
          tile.Layers.Add(_roadLayer);
    }
コード例 #12
0
    // Creates a random 3D path.
    private void CreatePath()
    {
      // Create a cyclic path.
      _path = new Path3F
      {
        PreLoop = CurveLoopType.Cycle,
        PostLoop = CurveLoopType.Cycle,
        SmoothEnds = true
      };

      // Add random path key points.
      for (int i = 0; i < 5; i++)
      {
        float x = RandomHelper.Random.NextFloat(-3, 3);
        float y = RandomHelper.Random.NextFloat(1, 3);
        float z = RandomHelper.Random.NextFloat(-3, 0);
        var key = new PathKey3F
        {
          Parameter = i,
          Point = new Vector3F(x, y, z),
          Interpolation = SplineInterpolation.CatmullRom
        };
        _path.Add(key);
      }

      // The last key uses the same position as the first key to create a closed path.
      var lastKey = new PathKey3F
      {
        Parameter = _path.Count,
        Point = _path[0].Point,
        Interpolation = SplineInterpolation.CatmullRom,
      };
      _path.Add(lastKey);

      // The current path parameter goes from 0 to 5. This path parameter is not linearly
      // proportional to the path length. This is not suitable for animations.
      // To move an object with constant speed along the path, the path parameter should
      // be linearly proportional to the length of the path.
      // ParameterizeByLength() changes the path parameter so that the path parameter
      // at the each key is equal to the length of path (measured from the first key position
      // to the current key position).
      // ParameterizeByLength() uses and iterative process, we end the process after 10 
      // iterations or when the error is less than 0.001f.
      _path.ParameterizeByLength(10, 0.001f);

      // Now, the parameter of the first key (_path[0]) is unchanged.
      // The parameter of the second key (_path[1]) is equal to the length of the path
      // from the first key to the second key.
      // The parameter of the third key (_path[2]) is equal to the length of the path
      // from the first key to the third key.
      // And so on. 

      // The parameter of the last key is equal to the length of the whole path:
      //   float pathLength = _path[_path.Count - 1].Parameter;

      // Important: The path parameter is now equal to the path length at the path keys.
      // But in general between path keys the path parameter is not linearly proportional
      // to the path length. This is due to the nature of splines.
      //
      // Example: 
      // Lets assume the second path key is at path length 100 and the third key is 
      // at path length 200.
      // If we call _path.GetPoint(100), we get the position of the second key.
      // If we call _path.GetPoint(200), we get the position ot the third key.
      // We can call _path.GetPoint(130) to get a position on the path between the second and
      // third key. But it is not guaranteed that the path is exactly 130 long at this position.
      // We only know that the point is somewhere between 100 and 200 path length.
      //
      // To get the path point at exactly the distance 130 from the path start, we have to call
      //   float parameter = _path.GetParameterFromLength(130, 10, 0.01f);
      // This uses an iterative root finding process to find the path parameter where the
      // path length is 130.
      // Then we can get the path position with 
      //   Vector3F pathPointAt130Length = _path.GetPoint(parameter).
    }
コード例 #13
0
    private void CreatePath()
    {
      // Create a cyclic path. (More information on paths can be found in the DigitalRune
      // Mathematics documentation and related samples.)
      _path = new Path3F
      {
        SmoothEnds = true,
        PreLoop = CurveLoopType.Cycle,
        PostLoop = CurveLoopType.Cycle
      };

      // The curvature of the path is defined by a number of path keys.
      _path.Add(new PathKey3F
      {
        Parameter = 0,                                  // The path parameter defines position of the path key on the curve.
        Point = new Vector3F(-4, 0.5f, -3),             // The world space position of the path key.
        Interpolation = SplineInterpolation.CatmullRom, // The type of interpolation that is used between this path key and the next.
      });
      _path.Add(new PathKey3F
      {
        Parameter = 1,
        Point = new Vector3F(-1, 0.5f, -5),
        Interpolation = SplineInterpolation.CatmullRom,
      });
      _path.Add(new PathKey3F
      {
        Parameter = 2,
        Point = new Vector3F(3, 0.5f, -4),
        Interpolation = SplineInterpolation.CatmullRom,
      });
      _path.Add(new PathKey3F
      {
        Parameter = 3,
        Point = new Vector3F(0, 0.5f, 0),
        Interpolation = SplineInterpolation.CatmullRom,
      });
      _path.Add(new PathKey3F
      {
        Parameter = 4,
        Point = new Vector3F(-3, 0.5f, 3),
        Interpolation = SplineInterpolation.CatmullRom,
      });
      _path.Add(new PathKey3F
      {
        Parameter = 5,
        Point = new Vector3F(-1, 0.5f, 5),
        Interpolation = SplineInterpolation.CatmullRom,
      });
      _path.Add(new PathKey3F
      {
        Parameter = 6,
        Point = new Vector3F(0, 0.5f, 0),
        Interpolation = SplineInterpolation.CatmullRom,
      });

      // The last key uses the same position as the first key to create a closed path.
      PathKey3F lastKey = new PathKey3F
      {
        Parameter = _path.Count,
        Point = _path[0].Point,
        Interpolation = SplineInterpolation.CatmullRom,
      };
      _path.Add(lastKey);

      // The current path parameter goes from 0 to 7. This path parameter is not linearly
      // proportional to the path length. This is not suitable for animations.
      // To move an object with constant speed along a path, the path parameter should
      // be linearly proportional to the length of the path.
      // ParameterizeByLength() changes the path parameter so that the path parameter
      // at the each key is equal to the length of path (measured from the first key position
      // to the current key position).
      // ParameterizeByLength() uses an iterative process, we end the process after 10 
      // iterations or when the error is less than 0.01f.
      _path.ParameterizeByLength(10, 0.01f);

      // Sample the path for rendering.
      int numberOfSamples = _pointList.Length - 1;
      float pathLength = _path.Last().Parameter;
      for (int i = 0; i <= numberOfSamples; i++)
      {
        Vector3F pointOnPath = _path.GetPoint(pathLength / numberOfSamples * i);
        _pointList[i] = pointOnPath;
      }
    }
コード例 #14
0
        public static void ClampTerrainToRoad(HeightField terrain, Path3F road,
            float defaultWidth, float defaultSideFalloff,
            int maxNumberOfIterations, float tolerance)
        {
            if (terrain == null)
            throw new ArgumentNullException("terrain");
              if (road == null)
            throw new ArgumentNullException("road");

              // Compute list of line segments. (2 points per line segment!)
              var flattenedPoints = new List<Vector3F>();
              road.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

              // Abort if path is empty.
              int numberOfLineSegments = flattenedPoints.Count / 2;
              if (numberOfLineSegments <= 0)
            return;

              // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
              float[] accumulatedLengths = new float[flattenedPoints.Count];
              accumulatedLengths[0] = 0;
              for (int i = 1; i < flattenedPoints.Count; i += 2)
              {
            Vector3F previous = flattenedPoints[i - 1];
            Vector3F current = flattenedPoints[i];
            float length = (current - previous).Length;

            accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
            if (i + 1 < flattenedPoints.Count)
              accumulatedLengths[i + 1] = accumulatedLengths[i];
              }

              // Create a mapping between accumulatedLength and the path keys.
              // (accumulatedLength --> key)
              var pathLengthsAndKeys = new List<Pair<float, TerrainRoadPathKey>>();
              {
            int index = 0;
            foreach (var key in road)
            {
              Vector3F position = key.Point;
              var roadKey = key as TerrainRoadPathKey;
              if (roadKey == null)
              {
            roadKey = new TerrainRoadPathKey
            {
              Point = key.Point,
              Width = defaultWidth,
              SideFalloff = defaultSideFalloff,
            };
              }

              for (; index < flattenedPoints.Count; index++)
              {
            if (Vector3F.AreNumericallyEqual(position, flattenedPoints[index]))
            {
              pathLengthsAndKeys.Add(new Pair<float, TerrainRoadPathKey>(accumulatedLengths[index], roadKey));
              break;
            }

            bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
            if (!isLastLineSegment)
              index++;
              }

              index++;
            }
              }

              // Create a list of interpolated road widths and side falloffs. (One entry for each entry in flattenedPoints.)
              var halfWidths = new float[flattenedPoints.Count];
              var sideFalloffs = new float[flattenedPoints.Count];
              int previousKeyIndex = 0;
              var previousKey = pathLengthsAndKeys[0];
              var nextKey = pathLengthsAndKeys[1];
              halfWidths[0] = 0.5f * pathLengthsAndKeys[0].Second.Width;
              sideFalloffs[0] = pathLengthsAndKeys[0].Second.SideFalloff;
              for (int i = 1; i < flattenedPoints.Count; i += 2)
              {
            if (accumulatedLengths[i] > nextKey.First)
            {
              previousKey = nextKey;
              previousKeyIndex++;
              nextKey = pathLengthsAndKeys[previousKeyIndex + 1];
            }

            float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
            halfWidths[i] = 0.5f * InterpolationHelper.Lerp(previousKey.Second.Width, nextKey.Second.Width, p);
            sideFalloffs[i] = InterpolationHelper.Lerp(previousKey.Second.SideFalloff, nextKey.Second.SideFalloff, p);

            if (i + 1 < flattenedPoints.Count)
            {
              halfWidths[i + 1] = halfWidths[i];
              sideFalloffs[i + 1] = sideFalloffs[i];
            }
              }

              // Get AABB of road with the side falloff.
              Aabb aabbWithSideFalloffs;
              {
            Vector3F p = flattenedPoints[0];
            float r = halfWidths[0] + sideFalloffs[0];
            aabbWithSideFalloffs = new Aabb(new Vector3F(p.X - r, 0, p.Z - r),
                                        new Vector3F(p.X + r, 0, p.Z + r));
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
              p = flattenedPoints[i];
              r = halfWidths[i] + sideFalloffs[i];
              aabbWithSideFalloffs.Grow(new Vector3F(p.X - r, 0, p.Z - r));
              aabbWithSideFalloffs.Grow(new Vector3F(p.X + r, 0, p.Z + r));
            }
              }

              // Terrain properties.
              int numberOfSamplesX = terrain.NumberOfSamplesX;
              int numberOfSamplesZ = terrain.NumberOfSamplesZ;
              int numberOfCellsX = numberOfSamplesX - 1;
              int numberOfCellsZ = numberOfSamplesZ - 1;
              float widthX = terrain.WidthX;
              float cellSizeX = widthX / numberOfCellsX;
              float widthZ = terrain.WidthZ;
              float cellSizeZ = widthZ / numberOfCellsZ;
              float cellSizeDiagonal = (float)Math.Sqrt(cellSizeX * cellSizeX + cellSizeZ * cellSizeZ);

              bool isClosed = Vector3F.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);

              {
            // Get the line segments which of the road border.
            List<Vector4F> segments = new List<Vector4F>();  // 2 points per segment.
            Vector3F lastOrthonormal = Vector3F.Right;
            Vector4F previousV1 = Vector4F.Zero;
            Vector4F previousV2 = Vector4F.Zero;
            for (int i = 0; i < flattenedPoints.Count; i++)
            {
              Vector3F start = flattenedPoints[i];

              Vector3F previous;
              bool isFirstPoint = (i == 0);
              if (!isFirstPoint)
            previous = flattenedPoints[i - 1];
              else if (isClosed && road.SmoothEnds)
            previous = flattenedPoints[flattenedPoints.Count - 2];
              else
            previous = start;

              Vector3F next;
              bool isLastPoint = (i + 1 == flattenedPoints.Count);
              if (!isLastPoint)
            next = flattenedPoints[i + 1];
              else if (isClosed && road.SmoothEnds)
            next = flattenedPoints[1];
              else
            next = start;

              Vector3F tangent = next - previous;

              Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
              if (!orthonormal.TryNormalize())
            orthonormal = lastOrthonormal;

              // Add 2 vertices two segments for the road side border.
              //
              //  pV1        pV2 (previous vertices)
              //  x           x
              //  |           |
              //  x           x
              //  v1          v2 (current vertices)
              //
              // We store the side falloff with the vertex:
              // Vectors are 4D. Height is y. Side falloff is w.
              Vector4F v1 = new Vector4F(start - orthonormal * (halfWidths[i] + 0), sideFalloffs[i]);
              Vector4F v2 = new Vector4F(start + orthonormal * (halfWidths[i] + 0), sideFalloffs[i]);

              if (i > 0)
              {
            segments.Add(previousV1);
            segments.Add(v1);
            segments.Add(previousV2);
            segments.Add(v2);

            if (isLastPoint && !isClosed)
            {
              // A segment for the end of the road.
              segments.Add(v1);
              segments.Add(v2);
            }
              }
              else
              {
            if (!isClosed)
            {
              // A segment for the start of the road.
              segments.Add(v1);
              segments.Add(v2);
            }
              }

              previousV1 = v1;
              previousV2 = v2;

              lastOrthonormal = orthonormal;

              // The flattened points list contains 2 points per line segment, which means that there
              // are duplicate intermediate points, which we skip.
              bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
              if (!isLastLineSegment)
            i++;
            }

            // Apply the side falloff to the terrain heights.
            // We use a padding where the road influence is 100% because we want road width to be flat
            // but that means that we also have to set some triangle vertices outside the road width to
            // full 100% road height.
            float padding = cellSizeDiagonal;
            ClampHeightsToLineSegments(terrain, aabbWithSideFalloffs, segments, padding);
              }

              // Clamp the terrain heights to the inner part of the road.
              // We create quads for the road mesh and clamp the heights to the quad triangles.
              {
            Vector3F previousV1 = Vector3F.Zero;
            Vector3F previousV2 = Vector3F.Zero;
            Vector3F lastOrthonormal = Vector3F.Right;
            for (int i = 0; i < flattenedPoints.Count; i++)
            {
              Vector3F start = flattenedPoints[i];

              Vector3F previous;
              bool isFirstPoint = (i == 0);
              if (!isFirstPoint)
            previous = flattenedPoints[i - 1];
              else if (isClosed && road.SmoothEnds)
            previous = flattenedPoints[flattenedPoints.Count - 2];
              else
            previous = start;

              Vector3F next;
              bool isLastPoint = (i + 1 == flattenedPoints.Count);
              if (!isLastPoint)
            next = flattenedPoints[i + 1];
              else if (isClosed && road.SmoothEnds)
            next = flattenedPoints[1];
              else
            next = start;

              Vector3F tangent = next - previous;

              Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
              if (!orthonormal.TryNormalize())
            orthonormal = lastOrthonormal;

              // Add 2 vertices to create a mesh like this:
              //
              //  pV1             pV2 (previous vertices)
              //  x---------------x
              //  |               |
              //  x---------------x
              //  v1              v2 (current vertices)
              //
              // Then we check all height samples against these triangles.

              // Vectors are 4D. Height is y. Influence is w.
              Vector3F v1 = start - orthonormal * halfWidths[i];
              Vector3F v2 = start + orthonormal * halfWidths[i];

              if (i > 0)
            ClampHeightsToQuad(terrain, previousV1, previousV2, v1, v2);

              previousV1 = v1;
              previousV2 = v2;

              lastOrthonormal = orthonormal;

              // The flattened points list contains 2 points per line segment, which means that there
              // are duplicate intermediate points, which we skip.
              bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
              if (!isLastLineSegment)
            i++;
            }
              }

              terrain.Invalidate();
        }
コード例 #15
0
        public static void CreateMesh(GraphicsDevice graphicsDevice, Path3F path, float defaultWidth,
            int maxNumberOfIterations, float tolerance,
            out Submesh submesh, out Aabb aabb, out float roadLength)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (path == null)
            throw new ArgumentNullException("path");

              // Compute list of line segments. (2 points per line segment!)
              var flattenedPoints = new List<Vector3F>();
              path.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

              // Abort if path is empty.
              int numberOfLineSegments = flattenedPoints.Count / 2;
              if (numberOfLineSegments <= 0)
              {
            submesh = null;
            aabb = new Aabb();
            roadLength = 0;
            return;
              }

              // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
              float[] accumulatedLengths = new float[flattenedPoints.Count];
              accumulatedLengths[0] = 0;
              for (int i = 1; i < flattenedPoints.Count; i += 2)
              {
            Vector3F previous = flattenedPoints[i - 1];
            Vector3F current = flattenedPoints[i];
            float length = (current - previous).Length;

            accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
            if (i + 1 < flattenedPoints.Count)
              accumulatedLengths[i + 1] = accumulatedLengths[i];
              }

              // Total road length.
              roadLength = accumulatedLengths[accumulatedLengths.Length - 1];

              // Create a mapping between accumulatedLength and the path key widths.
              // (accumulatedLength --> TerrainRoadPathKey.Width)
              var widthKeys = new List<Pair<float, float>>();
              {
            int index = 0;
            foreach (var key in path)
            {
              Vector3F position = key.Point;
              var roadKey = key as TerrainRoadPathKey;
              float width = (roadKey != null) ? roadKey.Width : defaultWidth;

              for (; index < flattenedPoints.Count; index++)
              {
            if (Vector3F.AreNumericallyEqual(position, flattenedPoints[index]))
            {
              widthKeys.Add(new Pair<float, float>(accumulatedLengths[index], width));
              break;
            }

            bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
            if (!isLastLineSegment)
              index++;
              }

              index++;
            }
              }

              // Create a list of interpolated road widths. (One entry for each entry in flattenedPoints.)
              var widths = new float[flattenedPoints.Count];
              int previousKeyIndex = 0;
              var previousKey = widthKeys[0];
              var nextKey = widthKeys[1];
              widths[0] = widthKeys[0].Second;
              for (int i = 1; i < flattenedPoints.Count; i += 2)
              {
            if (accumulatedLengths[i] > nextKey.First)
            {
              previousKey = nextKey;
              previousKeyIndex++;
              nextKey = widthKeys[previousKeyIndex + 1];
            }

            float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
            widths[i] = InterpolationHelper.Lerp(previousKey.Second, nextKey.Second, p);

            if (i + 1 < flattenedPoints.Count)
              widths[i + 1] = widths[i];
              }

              // Compute vertices and indices.
              var vertices = new List<TerrainLayerVertex>(numberOfLineSegments * 2 + 2);
              var indices = new List<int>(numberOfLineSegments * 6);  // Two triangles per line segment.
              Vector3F lastOrthonormal = Vector3F.UnitX;
              aabb = new Aabb(flattenedPoints[0], flattenedPoints[0]);
              bool isClosed = Vector3F.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);
              for (int i = 0; i < flattenedPoints.Count; i++)
              {
            Vector3F start = flattenedPoints[i];

            Vector3F previous;
            bool isFirstPoint = (i == 0);
            if (!isFirstPoint)
              previous = flattenedPoints[i - 1];
            else if (isClosed && path.SmoothEnds)
              previous = flattenedPoints[flattenedPoints.Count - 2];
            else
              previous = start;

            Vector3F next;
            bool isLastPoint = (i + 1 == flattenedPoints.Count);
            if (!isLastPoint)
              next = flattenedPoints[i + 1];
            else if (isClosed && path.SmoothEnds)
              next = flattenedPoints[1];
            else
              next = start;

            Vector3F tangent = next - previous;

            Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
            if (!orthonormal.TryNormalize())
              orthonormal = lastOrthonormal;

            // Add indices to add two triangles between the current and the next vertices.
            if (!isLastPoint)
            {
              int baseIndex = vertices.Count;

              //  2      3
              //   x----x
              //   |\   |   ^
              //   | \  |   | road
              //   |  \ |   | direction
              //   |   \|   |
              //   x----x
              //  0      1

              indices.Add(baseIndex);
              indices.Add(baseIndex + 1);
              indices.Add(baseIndex + 2);

              indices.Add(baseIndex + 1);
              indices.Add(baseIndex + 3);
              indices.Add(baseIndex + 2);
            }

            // Add two vertices.
            Vector3F leftVertex = start - orthonormal * (widths[i] / 2);
            Vector3F rightVertex = start + orthonormal * (widths[i] / 2);
            vertices.Add(new TerrainLayerVertex(new Vector2(leftVertex.X, leftVertex.Z), new Vector2(0, accumulatedLengths[i])));
            vertices.Add(new TerrainLayerVertex(new Vector2(rightVertex.X, rightVertex.Z), new Vector2(1, accumulatedLengths[i])));

            // Grow AABB
            aabb.Grow(leftVertex);
            aabb.Grow(rightVertex);

            lastOrthonormal = orthonormal;

            // The flattened points list contains 2 points per line segment, which means that there
            // are duplicate intermediate points, which we skip.
            bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
            if (!isLastLineSegment)
              i++;
              }

              Debug.Assert(vertices.Count == (numberOfLineSegments * 2 + 2));
              Debug.Assert(indices.Count == (numberOfLineSegments * 6));

              // The road is projected onto the terrain, therefore the computed y limits are not correct.
              // (unless the terrain was clamped to the road).
              aabb.Minimum.Y = 0;
              aabb.Maximum.Y = 0;

              // Convert to submesh.
              submesh = new Submesh
              {
            PrimitiveCount = indices.Count / 3,
            PrimitiveType = PrimitiveType.TriangleList,
            VertexCount = vertices.Count,
            VertexBuffer = new VertexBuffer(graphicsDevice, TerrainLayerVertex.VertexDeclaration, vertices.Count, BufferUsage.WriteOnly),
            IndexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.WriteOnly)
              };
              submesh.VertexBuffer.SetData(vertices.ToArray());
              submesh.IndexBuffer.SetData(indices.ToArray());
        }
コード例 #16
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void OneKeyCurvesTest()
        {
            // Test linear curves with 1 point
              Path3F curve = new Path3F();
              curve.Add(new PathKey3F()
              {
            Parameter = 1,
            Point = new Vector3F(1, 2, 0),
            Interpolation = SplineInterpolation.Linear,
              });
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Cycle;
              curve.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.CycleOffset;
              curve.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Oscillate;
              curve.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));

              // Test step curves with 1 point
              curve = new Path3F();
              curve.Add(new PathKey3F()
              {
            Parameter = 1,
            Point = new Vector3F(1, 2, 0),
            Interpolation = SplineInterpolation.StepLeft,
              });
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Cycle;
              curve.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.CycleOffset;
              curve.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Oscillate;
              curve.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));

              // Test B-spline curves with 1 point
              curve = new Path3F();
              curve.Add(new PathKey3F()
              {
            Parameter = 1,
            Point = new Vector3F(1, 2, 0),
            Interpolation = SplineInterpolation.BSpline,
              });
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Cycle;
              curve.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.CycleOffset;
              curve.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Oscillate;
              curve.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));

              // Test Catmull-Rom curves with 1 point
              curve = new Path3F();
              curve.Add(new PathKey3F()
              {
            Parameter = 1,
            Point = new Vector3F(1, 2, 0),
            Interpolation = SplineInterpolation.CatmullRom,
              });
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Cycle;
              curve.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.CycleOffset;
              curve.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Oscillate;
              curve.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));

              // Test Hermite curves with 1 point
              curve = new Path3F();
              curve.Add(new PathKey3F()
              {
            Parameter = 1,
            Point = new Vector3F(1, 2, 0),
            Interpolation = SplineInterpolation.Hermite,
            TangentIn = new Vector3F(2, -2, 0),
            TangentOut = new Vector3F(2, 2, 0),
              });
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 20, 0.01f));
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(3, 4, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(2, 2, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(2, 2, 0), curve.GetTangent(2));
              Assert.IsTrue(Numeric.AreEqual(new Vector3F(2, 2, 0).Length, curve.GetLength(0, 2, 10, 0.01f), 0.1f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(-1, 4, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(2, -2, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(2, -2, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.IsTrue(Numeric.AreEqual(new Vector3F(2, 2, 0).Length, curve.GetLength(0, 2, 10, 0.01f), 0.1f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(-1, 4, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(3, 4, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(2, -2, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(2, 2, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(2, 2, 0), curve.GetTangent(2));
              Assert.IsTrue(Numeric.AreEqual(new Vector3F(4, 4, 0).Length, curve.GetLength(0, 2, 10, 0.01f), 0.1f));
              curve.PreLoop = CurveLoopType.Cycle;
              curve.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.CycleOffset;
              curve.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Oscillate;
              curve.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));

              // Test Bezier curves with 1 point
              curve = new Path3F();
              curve.Add(new PathKey3F()
              {
            Parameter = 1,
            Point = new Vector3F(1, 2, 0),
            Interpolation = SplineInterpolation.Bezier,
            TangentIn = new Vector3F(1, 2, 0) - new Vector3F(2, -2, 0) / 3,
            TangentOut = new Vector3F(1, 2, 0) + new Vector3F(2, 2, 0) / 3,
              });
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Constant;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(3, 4, 0), curve.GetPoint(2)));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, 2, 0), curve.GetTangent(1)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, 2, 0), curve.GetTangent(2)));
              Assert.IsTrue(Numeric.AreEqual(new Vector3F(2, 2, 0).Length, curve.GetLength(0, 2, 10, 0.01f), 0.1f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(-1, 4, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, -2, 0), curve.GetTangent(0)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, -2, 0), curve.GetTangent(1)));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.IsTrue(Numeric.AreEqual(new Vector3F(2, 2, 0).Length, curve.GetLength(0, 2, 10, 0.01f), 0.1f));
              curve.PreLoop = CurveLoopType.Linear;
              curve.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(-1, 4, 0), curve.GetPoint(0));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(3, 4, 0), curve.GetPoint(2)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, -2, 0), curve.GetTangent(0)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, 2, 0), curve.GetTangent(1)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(2, 2, 0), curve.GetTangent(2)));
              Assert.IsTrue(Numeric.AreEqual(new Vector3F(4, 4, 0).Length, curve.GetLength(0, 2, 10, 0.01f), 0.1f));
              curve.PreLoop = CurveLoopType.Cycle;
              curve.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.CycleOffset;
              curve.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
              curve.PreLoop = CurveLoopType.Oscillate;
              curve.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
              Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(2));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(1));
              Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(2));
              Assert.AreEqual(0, curve.GetLength(0, 2, 10, 0.01f));
        }
コード例 #17
0
        public void LoopParameter()
        {
            Path3F empty = new Path3F();
              empty.Sort();
              Assert.AreEqual(3, empty.LoopParameter(3));
              Assert.AreEqual(false, empty.IsInMirroredOscillation(3));

              Path3F path = CreatePath();
              path.PreLoop = CurveLoopType.Constant;
              path.PostLoop = CurveLoopType.Oscillate;
              Assert.AreEqual(10, path.LoopParameter(3));
              Assert.AreEqual(false, path.IsInMirroredOscillation(3));
              Assert.AreEqual(10, path.LoopParameter(10));
              Assert.AreEqual(false, path.IsInMirroredOscillation(10));
              Assert.AreEqual(13, path.LoopParameter(13));
              Assert.AreEqual(false, path.IsInMirroredOscillation(13));
              Assert.AreEqual(40, path.LoopParameter(40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(40));
              Assert.AreEqual(35, path.LoopParameter(45));
              Assert.AreEqual(true, path.IsInMirroredOscillation(45));
              Assert.AreEqual(14, path.LoopParameter(74));
              Assert.AreEqual(false, path.IsInMirroredOscillation(74));

              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Cycle;
              Assert.AreEqual(3, path.LoopParameter(3));
              Assert.AreEqual(false, path.IsInMirroredOscillation(3));
              Assert.AreEqual(10, path.LoopParameter(10));
              Assert.AreEqual(false, path.IsInMirroredOscillation(10));
              Assert.AreEqual(13, path.LoopParameter(13));
              Assert.AreEqual(false, path.IsInMirroredOscillation(13));
              Assert.AreEqual(40, path.LoopParameter(40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(40));
              Assert.AreEqual(15, path.LoopParameter(45));
              Assert.AreEqual(false, path.IsInMirroredOscillation(45));
              Assert.AreEqual(14, path.LoopParameter(74));
              Assert.AreEqual(false, path.IsInMirroredOscillation(74));

              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.CycleOffset;
              Assert.AreEqual(20, path.LoopParameter(-40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(-40));
              Assert.AreEqual(33, path.LoopParameter(3));
              Assert.AreEqual(false, path.IsInMirroredOscillation(3));
              Assert.AreEqual(10, path.LoopParameter(10));
              Assert.AreEqual(false, path.IsInMirroredOscillation(10));
              Assert.AreEqual(13, path.LoopParameter(13));
              Assert.AreEqual(false, path.IsInMirroredOscillation(13));
              Assert.AreEqual(40, path.LoopParameter(40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(40));
              Assert.AreEqual(15, path.LoopParameter(45));
              Assert.AreEqual(false, path.IsInMirroredOscillation(45));
              Assert.AreEqual(14, path.LoopParameter(74));
              Assert.AreEqual(false, path.IsInMirroredOscillation(74));
              Assert.AreEqual(20, path.LoopParameter(200));
              Assert.AreEqual(false, path.IsInMirroredOscillation(200));

              path.PreLoop = CurveLoopType.CycleOffset;
              path.PostLoop = CurveLoopType.Linear;
              Assert.AreEqual(20, path.LoopParameter(-40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(-40));
              Assert.AreEqual(33, path.LoopParameter(3));
              Assert.AreEqual(false, path.IsInMirroredOscillation(3));
              Assert.AreEqual(10, path.LoopParameter(10));
              Assert.AreEqual(false, path.IsInMirroredOscillation(10));
              Assert.AreEqual(13, path.LoopParameter(13));
              Assert.AreEqual(false, path.IsInMirroredOscillation(13));
              Assert.AreEqual(40, path.LoopParameter(40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(40));
              Assert.AreEqual(45, path.LoopParameter(45));
              Assert.AreEqual(false, path.IsInMirroredOscillation(45));
              Assert.AreEqual(74, path.LoopParameter(74));
              Assert.AreEqual(false, path.IsInMirroredOscillation(74));
              Assert.AreEqual(200, path.LoopParameter(200));
              Assert.AreEqual(false, path.IsInMirroredOscillation(200));

              path.PreLoop = CurveLoopType.Oscillate;
              path.PostLoop = CurveLoopType.Constant;
              Assert.AreEqual(20, path.LoopParameter(-40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(-40));
              Assert.AreEqual(17, path.LoopParameter(3));
              Assert.AreEqual(true, path.IsInMirroredOscillation(3));
              Assert.AreEqual(10, path.LoopParameter(10));
              Assert.AreEqual(false, path.IsInMirroredOscillation(10));
              Assert.AreEqual(13, path.LoopParameter(13));
              Assert.AreEqual(false, path.IsInMirroredOscillation(13));
              Assert.AreEqual(40, path.LoopParameter(40));
              Assert.AreEqual(false, path.IsInMirroredOscillation(40));
              Assert.AreEqual(40, path.LoopParameter(45));
              Assert.AreEqual(false, path.IsInMirroredOscillation(45));
              Assert.AreEqual(40, path.LoopParameter(74));
              Assert.AreEqual(false, path.IsInMirroredOscillation(74));
              Assert.AreEqual(40, path.LoopParameter(200));
              Assert.AreEqual(false, path.IsInMirroredOscillation(200));
        }
コード例 #18
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void ParameterizeByLength()
        {
            Path3F empty = new Path3F();
              empty.Sort();
              empty.ParameterizeByLength(20, 0.001f); // No exception, do nothing.

              Path3F path = CreatePath();
              Path3F lengthPath = CreatePath();
              lengthPath.ParameterizeByLength(20, 0.001f);

              Assert.AreEqual(0, lengthPath[0].Parameter);
              Assert.AreEqual(3, lengthPath[1].Parameter);
              Assert.AreEqual(3, lengthPath[2].Parameter);
              Assert.AreEqual(3, lengthPath[3].Parameter);

              float step = 0.001f;
              float length = 3;
              int i = 4;
              float u = 20;
              Vector3F oldPoint = path.GetPoint(u);
              for (; u < 51 && i<10; u += step)
              {
            if (Numeric.AreEqual(u, path[i].Parameter))
            {
              Assert.IsTrue(Numeric.AreEqual(length, lengthPath[i].Parameter, 0.01f));

              // Set explicit values against numerical problems.
              length = lengthPath[i].Parameter;
              u = path[i].Parameter;
              oldPoint = path.GetPoint(u);

              i++;
            }
            Vector3F newPoint = path.GetPoint(u + step);
            length += (newPoint - oldPoint).Length;
            oldPoint = newPoint;
              }
              Assert.AreEqual(10, i); // Have we checked all keys?

            path.PreLoop = CurveLoopType.Constant;
              path.PostLoop = CurveLoopType.Oscillate;

              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Cycle;

              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.CycleOffset;

              path.PreLoop = CurveLoopType.CycleOffset;
              path.PostLoop = CurveLoopType.Linear;

              path.PreLoop = CurveLoopType.Oscillate;
              path.PostLoop = CurveLoopType.Constant;
        }
コード例 #19
0
    // Add a random path.
    private void CreateRandomPath()
    {
      var path = new Path3F();
      var point = new Vector3F(0, 0, 0);
      path.Add(new PathKey3F
      {
        Interpolation = SplineInterpolation.CatmullRom,
        Parameter = 0,
        Point = point
      });
      for (int i = 1; i < 10; i++)
      {
        point += RandomHelper.Random.NextQuaternionF().Rotate(new Vector3F(0, 0.5f, 0));
        path.Add(new PathKey3F
        {
          Interpolation = SplineInterpolation.CatmullRom,
          Parameter = i,
          Point = point
        });
      }
      var pathFigure = new PathFigure3F();
      pathFigure.Segments.Add(path);

      var pathLineNode = new FigureNode(pathFigure)
      {
        Name = "RandomPath",
        PoseLocal = new Pose(new Vector3F(4, 1, 2)),
        StrokeThickness = 3,
        StrokeColor = new Vector3F(0.5f, 0.3f, 1),
        StrokeAlpha = 1f,
        DashInWorldSpace = true,
        StrokeDashPattern = new Vector4F(10, 1, 1, 1) / 100,
      };
      _scene.Children.Add(pathLineNode);
    }
コード例 #20
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
 public void TwoKeyCurvesTest()
 {
     Path3F curve = new Path3F();
       curve.Add(new PathKey3F()
           {
             Parameter = 1,
             Point = new Vector3F(1, 2, 0),
             Interpolation = SplineInterpolation.CatmullRom,
           });
       curve.Add(new PathKey3F()
           {
             Parameter = 3,
             Point = new Vector3F(3, 4, 0),
             Interpolation = SplineInterpolation.CatmullRom,
           });
       curve.PreLoop = CurveLoopType.Constant;
       curve.PostLoop = CurveLoopType.Constant;
       Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(0));
       Assert.AreEqual(new Vector3F(1, 2, 0), curve.GetPoint(1));
       Assert.AreEqual(new Vector3F(2, 3, 0), curve.GetPoint(2));
       Assert.AreEqual(new Vector3F(3, 4, 0), curve.GetPoint(3));
       Assert.AreEqual(new Vector3F(3, 4, 0), curve.GetPoint(4));
       Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(0));
       Assert.AreEqual(new Vector3F(1, 1, 0), curve.GetTangent(1));
       Assert.AreEqual(new Vector3F(1, 1, 0), curve.GetTangent(2));
       Assert.AreEqual(new Vector3F(1, 1, 0), curve.GetTangent(3));
       Assert.AreEqual(new Vector3F(0, 0, 0), curve.GetTangent(4));
       Assert.IsTrue(Numeric.AreEqual(new Vector3F(2, 2, 0).Length, curve.GetLength(0, 4, 10, 0.01f), 0.01f));
       curve.PreLoop = CurveLoopType.Linear;
       curve.PostLoop = CurveLoopType.Linear;
       curve.PreLoop = CurveLoopType.Cycle;
       curve.PostLoop = CurveLoopType.Cycle;
       curve.PreLoop = CurveLoopType.CycleOffset;
       curve.PostLoop = CurveLoopType.CycleOffset;
       curve.PreLoop = CurveLoopType.Oscillate;
       curve.PostLoop = CurveLoopType.Oscillate;
 }
コード例 #21
0
        // Creates a random 3D path.
        private void CreatePath()
        {
            // Create a cyclic path.
            _path = new Path3F
            {
                PreLoop    = CurveLoopType.Cycle,
                PostLoop   = CurveLoopType.Cycle,
                SmoothEnds = true
            };

            // Add random path key points.
            for (int i = 0; i < 5; i++)
            {
                float x   = RandomHelper.Random.NextFloat(-3, 3);
                float y   = RandomHelper.Random.NextFloat(1, 3);
                float z   = RandomHelper.Random.NextFloat(-3, 0);
                var   key = new PathKey3F
                {
                    Parameter     = i,
                    Point         = new Vector3F(x, y, z),
                    Interpolation = SplineInterpolation.CatmullRom
                };
                _path.Add(key);
            }

            // The last key uses the same position as the first key to create a closed path.
            var lastKey = new PathKey3F
            {
                Parameter     = _path.Count,
                Point         = _path[0].Point,
                Interpolation = SplineInterpolation.CatmullRom,
            };

            _path.Add(lastKey);

            // The current path parameter goes from 0 to 5. This path parameter is not linearly
            // proportional to the path length. This is not suitable for animations.
            // To move an object with constant speed along the path, the path parameter should
            // be linearly proportional to the length of the path.
            // ParameterizeByLength() changes the path parameter so that the path parameter
            // at the each key is equal to the length of path (measured from the first key position
            // to the current key position).
            // ParameterizeByLength() uses and iterative process, we end the process after 10
            // iterations or when the error is less than 0.001f.
            _path.ParameterizeByLength(10, 0.001f);

            // Now, the parameter of the first key (_path[0]) is unchanged.
            // The parameter of the second key (_path[1]) is equal to the length of the path
            // from the first key to the second key.
            // The parameter of the third key (_path[2]) is equal to the length of the path
            // from the first key to the third key.
            // And so on.

            // The parameter of the last key is equal to the length of the whole path:
            //   float pathLength = _path[_path.Count - 1].Parameter;

            // Important: The path parameter is now equal to the path length at the path keys.
            // But in general between path keys the path parameter is not linearly proportional
            // to the path length. This is due to the nature of splines.
            //
            // Example:
            // Lets assume the second path key is at path length 100 and the third key is
            // at path length 200.
            // If we call _path.GetPoint(100), we get the position of the second key.
            // If we call _path.GetPoint(200), we get the position ot the third key.
            // We can call _path.GetPoint(130) to get a position on the path between the second and
            // third key. But it is not guaranteed that the path is exactly 130 long at this position.
            // We only know that the point is somewhere between 100 and 200 path length.
            //
            // To get the path point at exactly the distance 130 from the path start, we have to call
            //   float parameter = _path.GetParameterFromLength(130, 10, 0.01f);
            // This uses an iterative root finding process to find the path parameter where the
            // path length is 130.
            // Then we can get the path position with
            //   Vector3F pathPointAt130Length = _path.GetPoint(parameter).
        }
コード例 #22
0
        private void CreateRoad()
        {
            //RandomHelper.Random = new Random(1234567);

            // Set isClosed to true join the start and the end of the road.
            bool isClosed = false;

            // Create a new TerrainRoadLayer which paints a road onto the terrain.
            // The road itself is defined by a mesh which is set later.
            _roadLayer = new TerrainRoadLayer(GraphicsService)
            {
                DiffuseColor    = new Vector3(0.5f),
                SpecularColor   = new Vector3(1),
                DiffuseTexture  = ContentManager.Load <Texture2D>("Terrain/Road-Asphalt-Diffuse"),
                NormalTexture   = ContentManager.Load <Texture2D>("Terrain/Road-Asphalt-Normal"),
                SpecularTexture = ContentManager.Load <Texture2D>("Terrain/Road-Asphalt-Specular"),
                HeightTexture   = ContentManager.Load <Texture2D>("Terrain/Road-Asphalt-Height"),

                // The size of the tileable detail textures in world space units.
                TileSize = 5,

                // The border blend range controls how the border of the road fades out.
                // We fade out 5% of the texture on each side of the road.
                BorderBlendRange = new Vector4(0.05f, 0.05f, 0.05f, 0.05f),
            };

            // Create 3D spline path with some semi-random control points.
            _roadPath = new Path3F
            {
                PreLoop    = isClosed ? CurveLoopType.Cycle : CurveLoopType.Linear,
                PostLoop   = isClosed ? CurveLoopType.Cycle : CurveLoopType.Linear,
                SmoothEnds = isClosed,
            };

            // The position of the next path key.
            Vector3 position = new Vector3(
                RandomHelper.Random.NextFloat(-20, 20),
                0,
                RandomHelper.Random.NextFloat(-20, 20));

            // The direction to the next path key.
            Vector3 direction = Quaternion.CreateRotationY(RandomHelper.Random.NextFloat(0, 10)).Rotate(Vector3.Forward);

            // Add path keys.
            for (int j = 0; j < 10; j++)
            {
                // Instead of a normal PathKey3F, we use a TerrainRoadPathKey which allows to control
                // the road with and the side falloff.
                var key = new TerrainRoadPathKey
                {
                    Interpolation = SplineInterpolation.CatmullRom,
                    Parameter     = j,
                    Point         = position,

                    // The width of the road at the path key.
                    Width = RandomHelper.Random.NextFloat(6, 10),

                    // The side falloff (which is used in ClampTerrainToRoad to blend the height values with
                    // the road).
                    SideFalloff = RandomHelper.Random.NextFloat(20, 40),
                };

                _roadPath.Add(key);

                // Get next random position and direction.
                position   += direction * RandomHelper.Random.NextFloat(20, 40);
                position.Y += RandomHelper.Random.NextFloat(-2, 2);
                direction   = Quaternion.CreateRotationY(RandomHelper.Random.NextFloat(-1, 1))
                              .Rotate(direction);
            }

            if (isClosed)
            {
                // To create a closed path the first and the last key should be identical.
                _roadPath[_roadPath.Count - 1].Point = _roadPath[0].Point;
                ((TerrainRoadPathKey)_roadPath[_roadPath.Count - 1]).Width       = ((TerrainRoadPathKey)_roadPath[0]).Width;
                ((TerrainRoadPathKey)_roadPath[_roadPath.Count - 1]).SideFalloff =
                    ((TerrainRoadPathKey)_roadPath[0]).SideFalloff;

                // Since the path is closed we do not have to fade out the start and the end of the road.
                _roadLayer.BorderBlendRange *= new Vector4(1, 0, 1, 0);
            }

            // Convert the path to a mesh.
            Submesh roadSubmesh;
            Aabb    roadAabb;
            float   roadLength;

            TerrainRoadLayer.CreateMesh(
                GraphicsService.GraphicsDevice,
                _roadPath,
                4,
                10,
                0.1f,
                out roadSubmesh,
                out roadAabb,
                out roadLength);

            // Set the mesh in the road layer.
            _roadLayer.SetMesh(roadSubmesh, roadAabb, roadLength, true);

            if (isClosed)
            {
                // When the path is closed, the end texture and the start texture coordinates should
                // match. This is the case if (roadLength / tileSize) is an integer.
                var numberOfTiles = (int)(roadLength / _roadLayer.TileSize);
                _roadLayer.TileSize = roadLength / numberOfTiles;
            }

            // The road layer is added to the layers of a tile. We have to add the road to each terrain
            // tile which it overlaps.
            foreach (var tile in _terrainObject.TerrainNode.Terrain.Tiles)
            {
                if (GeometryHelper.HaveContact(tile.Aabb, _roadLayer.Aabb.Value))
                {
                    tile.Layers.Add(_roadLayer);
                }
            }
        }
コード例 #23
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void GetParameterByLength()
        {
            Path3F empty = new Path3F();
              empty.ParameterizeByLength(20, 0.001f); // No exception, do nothing.
              Assert.IsTrue(float.IsNaN(empty.GetParameterFromLength(10, 20, 0.1f)));

              Path3F path = CreatePath();
              path.ParameterizeByLength(20, 0.001f);

              Assert.AreEqual(0, path.GetParameterFromLength(0, 20, 0.001f));
              Assert.AreEqual(3, path.GetParameterFromLength(3, 20, 0.001f));
              Assert.AreEqual(path[4].Parameter, path.GetParameterFromLength(path[4].Parameter, 20, 0.01f));
              Assert.AreEqual(path[5].Parameter, path.GetParameterFromLength(path[5].Parameter, 20, 0.01f));
              Assert.AreEqual(path[6].Parameter, path.GetParameterFromLength(path[6].Parameter, 20, 0.01f));
              Assert.AreEqual(path[7].Parameter, path.GetParameterFromLength(path[7].Parameter, 20, 0.01f));
              Assert.AreEqual(path[8].Parameter, path.GetParameterFromLength(path[8].Parameter, 20, 0.01f));
              Assert.AreEqual(path[9].Parameter, path.GetParameterFromLength(path[9].Parameter, 20, 0.01f));

              float pathLength = path[9].Parameter;

              float desiredLength = 11;
              float actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.01f));

              desiredLength = 26;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.01f));

              desiredLength = 33.5f;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.001f), 20, 0.001f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.01f));

              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Linear;
              desiredLength = 60;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.001f), 20, 0.001f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));

              desiredLength = -10f;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.001f), 20, 0.001f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.01f));

              path.PreLoop = CurveLoopType.CycleOffset;
              path.PostLoop = CurveLoopType.CycleOffset;
              path.ParameterizeByLength(20, 0.001f);
              desiredLength = -90;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = -50;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = -30;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 50;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 100;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 130;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 200;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));

              path.PreLoop = CurveLoopType.Oscillate;
              path.PostLoop = CurveLoopType.Cycle;
              path.ParameterizeByLength(20, 0.001f);
              desiredLength = -110;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(-3 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(-2 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = -50;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(-2 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(-1 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = -30;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(-1 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(0 > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 50;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(1 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(2 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 110;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(2 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(3 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 130;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(3 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(4 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 190;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(4 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(5 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.2f));

              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.Oscillate;
              path.ParameterizeByLength(20, 0.001f);
              desiredLength = -90;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(-3 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(-2 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = -50;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(-2 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(-1 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = -30;
              actualLength = -path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(-1 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(0 > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 50;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(2 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 110;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(2 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(3 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 130;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(3 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(4 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));
              desiredLength = 210;
              actualLength = path.GetLength(0, path.GetParameterFromLength(desiredLength, 20, 0.01f), 20, 0.01f);
              Assert.IsTrue(5 * pathLength < path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(6 * pathLength > path.GetParameterFromLength(desiredLength, 20, 0.01f));
              Assert.IsTrue(Numeric.AreEqual(desiredLength, actualLength, 0.1f));

              // Test path with zero length.
              path = new Path3F();
              path.Add(new PathKey3F()
              {
            Parameter = 10,
            Point = new Vector3F(0, 0, 1),
            Interpolation = SplineInterpolation.Linear,
            TangentIn = new Vector3F(1, 0, 0),
            TangentOut = new Vector3F(1, 0, 0),
              });
              path.ParameterizeByLength(20, 0.001f);
              Assert.AreEqual(0, path.GetParameterFromLength(0, 20, 0.1f));
              path.Add(new PathKey3F()
              {
            Parameter = 20,
            Point = new Vector3F(0, 0, 1),
            Interpolation = SplineInterpolation.Linear,
            TangentIn = new Vector3F(1, 0, 0),
            TangentOut = new Vector3F(1, 0, 0),
              });
              path.ParameterizeByLength(20, 0.001f);
              Assert.AreEqual(0, path.GetParameterFromLength(0, 20, 0.1f));
        }
コード例 #24
0
        private Path3F CreatePath()
        {
            Path3F path = new Path3F();

            path.Add(new PathKey3F()
            {
                Parameter     = 10,
                Point         = new Vector3(1, 2, 3),
                Interpolation = SplineInterpolation.StepLeft,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 15,
                Point         = new Vector3(4, 5, 7),
                Interpolation = SplineInterpolation.StepCentered,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 18,
                Point         = new Vector3(5, 7, 10),
                Interpolation = SplineInterpolation.StepRight,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 20,
                Point         = new Vector3(5, 7, 13),
                Interpolation = SplineInterpolation.Linear,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 25,
                Point         = new Vector3(6, 7, 14),
                Interpolation = SplineInterpolation.Bezier,
                TangentIn     = new Vector3(5, 6, 13),
                TangentOut    = new Vector3(7, 8, 15),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 31,
                Point         = new Vector3(8, 10, 16),
                Interpolation = SplineInterpolation.BSpline,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 35,
                Point         = new Vector3(10, 12, 14),
                Interpolation = SplineInterpolation.Hermite,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            path.Add(new PathKey3F()
            {
                Parameter     = 40,
                Point         = new Vector3(10, 14, 8),
                Interpolation = SplineInterpolation.CatmullRom,
                TangentIn     = new Vector3(1, 0, 0),
                TangentOut    = new Vector3(1, 0, 0),
            });
            return(path);
        }
コード例 #25
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
 private Path3F CreatePath()
 {
     Path3F path = new Path3F();
       path.Add(new PathKey3F()
       {
     Parameter = 10,
     Point = new Vector3F(0, 0, 1),
     Interpolation = SplineInterpolation.Linear,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 12,
     Point = new Vector3F(1, 2, 3),
     Interpolation = SplineInterpolation.StepLeft,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 15,
     Point = new Vector3F(4, 5, 7),
     Interpolation = SplineInterpolation.StepCentered,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 18,
     Point = new Vector3F(5, 7, 10),
     Interpolation = SplineInterpolation.StepRight,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 20,
     Point = new Vector3F(5, 7, 13),
     Interpolation = SplineInterpolation.Linear,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 31,
     Point = new Vector3F(8, 10, 16),
     Interpolation = SplineInterpolation.BSpline,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 35,
     Point = new Vector3F(10, 12, 14),
     Interpolation = SplineInterpolation.Hermite,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 25,
     Point = new Vector3F(6, 7, 14),
     Interpolation = SplineInterpolation.Bezier,
     TangentIn = new Vector3F(5, 6, 13),
     TangentOut = new Vector3F(7, 8, 15),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 40,
     Point = new Vector3F(10, 14, 8),
     Interpolation = SplineInterpolation.CatmullRom,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Add(new PathKey3F()
       {
     Parameter = 50,
     Point = new Vector3F(20, 14, 8),
     Interpolation = SplineInterpolation.CatmullRom,
     TangentIn = new Vector3F(1, 0, 0),
     TangentOut = new Vector3F(1, 0, 0),
       });
       path.Sort();
       return path;
 }
コード例 #26
0
        public void LoopParameter()
        {
            Path3F empty = new Path3F();

            empty.Sort();
            Assert.AreEqual(3, empty.LoopParameter(3));
            Assert.AreEqual(false, empty.IsInMirroredOscillation(3));

            Path3F path = CreatePath();

            path.PreLoop  = CurveLoopType.Constant;
            path.PostLoop = CurveLoopType.Oscillate;
            Assert.AreEqual(10, path.LoopParameter(3));
            Assert.AreEqual(false, path.IsInMirroredOscillation(3));
            Assert.AreEqual(10, path.LoopParameter(10));
            Assert.AreEqual(false, path.IsInMirroredOscillation(10));
            Assert.AreEqual(13, path.LoopParameter(13));
            Assert.AreEqual(false, path.IsInMirroredOscillation(13));
            Assert.AreEqual(40, path.LoopParameter(40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(40));
            Assert.AreEqual(35, path.LoopParameter(45));
            Assert.AreEqual(true, path.IsInMirroredOscillation(45));
            Assert.AreEqual(14, path.LoopParameter(74));
            Assert.AreEqual(false, path.IsInMirroredOscillation(74));

            path.PreLoop  = CurveLoopType.Linear;
            path.PostLoop = CurveLoopType.Cycle;
            Assert.AreEqual(3, path.LoopParameter(3));
            Assert.AreEqual(false, path.IsInMirroredOscillation(3));
            Assert.AreEqual(10, path.LoopParameter(10));
            Assert.AreEqual(false, path.IsInMirroredOscillation(10));
            Assert.AreEqual(13, path.LoopParameter(13));
            Assert.AreEqual(false, path.IsInMirroredOscillation(13));
            Assert.AreEqual(40, path.LoopParameter(40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(40));
            Assert.AreEqual(15, path.LoopParameter(45));
            Assert.AreEqual(false, path.IsInMirroredOscillation(45));
            Assert.AreEqual(14, path.LoopParameter(74));
            Assert.AreEqual(false, path.IsInMirroredOscillation(74));

            path.PreLoop  = CurveLoopType.Cycle;
            path.PostLoop = CurveLoopType.CycleOffset;
            Assert.AreEqual(20, path.LoopParameter(-40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(-40));
            Assert.AreEqual(33, path.LoopParameter(3));
            Assert.AreEqual(false, path.IsInMirroredOscillation(3));
            Assert.AreEqual(10, path.LoopParameter(10));
            Assert.AreEqual(false, path.IsInMirroredOscillation(10));
            Assert.AreEqual(13, path.LoopParameter(13));
            Assert.AreEqual(false, path.IsInMirroredOscillation(13));
            Assert.AreEqual(40, path.LoopParameter(40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(40));
            Assert.AreEqual(15, path.LoopParameter(45));
            Assert.AreEqual(false, path.IsInMirroredOscillation(45));
            Assert.AreEqual(14, path.LoopParameter(74));
            Assert.AreEqual(false, path.IsInMirroredOscillation(74));
            Assert.AreEqual(20, path.LoopParameter(200));
            Assert.AreEqual(false, path.IsInMirroredOscillation(200));

            path.PreLoop  = CurveLoopType.CycleOffset;
            path.PostLoop = CurveLoopType.Linear;
            Assert.AreEqual(20, path.LoopParameter(-40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(-40));
            Assert.AreEqual(33, path.LoopParameter(3));
            Assert.AreEqual(false, path.IsInMirroredOscillation(3));
            Assert.AreEqual(10, path.LoopParameter(10));
            Assert.AreEqual(false, path.IsInMirroredOscillation(10));
            Assert.AreEqual(13, path.LoopParameter(13));
            Assert.AreEqual(false, path.IsInMirroredOscillation(13));
            Assert.AreEqual(40, path.LoopParameter(40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(40));
            Assert.AreEqual(45, path.LoopParameter(45));
            Assert.AreEqual(false, path.IsInMirroredOscillation(45));
            Assert.AreEqual(74, path.LoopParameter(74));
            Assert.AreEqual(false, path.IsInMirroredOscillation(74));
            Assert.AreEqual(200, path.LoopParameter(200));
            Assert.AreEqual(false, path.IsInMirroredOscillation(200));

            path.PreLoop  = CurveLoopType.Oscillate;
            path.PostLoop = CurveLoopType.Constant;
            Assert.AreEqual(20, path.LoopParameter(-40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(-40));
            Assert.AreEqual(17, path.LoopParameter(3));
            Assert.AreEqual(true, path.IsInMirroredOscillation(3));
            Assert.AreEqual(10, path.LoopParameter(10));
            Assert.AreEqual(false, path.IsInMirroredOscillation(10));
            Assert.AreEqual(13, path.LoopParameter(13));
            Assert.AreEqual(false, path.IsInMirroredOscillation(13));
            Assert.AreEqual(40, path.LoopParameter(40));
            Assert.AreEqual(false, path.IsInMirroredOscillation(40));
            Assert.AreEqual(40, path.LoopParameter(45));
            Assert.AreEqual(false, path.IsInMirroredOscillation(45));
            Assert.AreEqual(40, path.LoopParameter(74));
            Assert.AreEqual(false, path.IsInMirroredOscillation(74));
            Assert.AreEqual(40, path.LoopParameter(200));
            Assert.AreEqual(false, path.IsInMirroredOscillation(200));
        }
コード例 #27
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void GetPointShouldReturnNanIfPathIsEmpty()
        {
            Path3F empty = new Path3F();
              empty.Sort();

              Vector3F p = empty.GetPoint(-0.5f);
              Assert.IsNaN(p.X);
              Assert.IsNaN(p.Y);
              Assert.IsNaN(p.Z);

              p = empty.GetPoint(0);
              Assert.IsNaN(p.X);
              Assert.IsNaN(p.Y);
              Assert.IsNaN(p.Z);

              p = empty.GetPoint(0.5f);
              Assert.IsNaN(p.X);
              Assert.IsNaN(p.Y);
              Assert.IsNaN(p.Z);
        }
コード例 #28
0
        public static void CreateMesh(GraphicsDevice graphicsDevice, Path3F path, float defaultWidth,
                                      int maxNumberOfIterations, float tolerance,
                                      out Submesh submesh, out Aabb aabb, out float roadLength)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }

            // Compute list of line segments. (2 points per line segment!)
            var flattenedPoints = new List <Vector3F>();

            path.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

            // Abort if path is empty.
            int numberOfLineSegments = flattenedPoints.Count / 2;

            if (numberOfLineSegments <= 0)
            {
                submesh    = null;
                aabb       = new Aabb();
                roadLength = 0;
                return;
            }

            // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
            float[] accumulatedLengths = new float[flattenedPoints.Count];
            accumulatedLengths[0] = 0;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                Vector3F previous = flattenedPoints[i - 1];
                Vector3F current  = flattenedPoints[i];
                float    length   = (current - previous).Length;

                accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
                if (i + 1 < flattenedPoints.Count)
                {
                    accumulatedLengths[i + 1] = accumulatedLengths[i];
                }
            }

            // Total road length.
            roadLength = accumulatedLengths[accumulatedLengths.Length - 1];

            // Create a mapping between accumulatedLength and the path key widths.
            // (accumulatedLength --> TerrainRoadPathKey.Width)
            var widthKeys = new List <Pair <float, float> >();
            {
                int index = 0;
                foreach (var key in path)
                {
                    Vector3F position = key.Point;
                    var      roadKey  = key as TerrainRoadPathKey;
                    float    width    = (roadKey != null) ? roadKey.Width : defaultWidth;

                    for (; index < flattenedPoints.Count; index++)
                    {
                        if (Vector3F.AreNumericallyEqual(position, flattenedPoints[index]))
                        {
                            widthKeys.Add(new Pair <float, float>(accumulatedLengths[index], width));
                            break;
                        }

                        bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
                        if (!isLastLineSegment)
                        {
                            index++;
                        }
                    }

                    index++;
                }
            }

            // Create a list of interpolated road widths. (One entry for each entry in flattenedPoints.)
            var widths           = new float[flattenedPoints.Count];
            int previousKeyIndex = 0;
            var previousKey      = widthKeys[0];
            var nextKey          = widthKeys[1];

            widths[0] = widthKeys[0].Second;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                if (accumulatedLengths[i] > nextKey.First)
                {
                    previousKey = nextKey;
                    previousKeyIndex++;
                    nextKey = widthKeys[previousKeyIndex + 1];
                }

                float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
                widths[i] = InterpolationHelper.Lerp(previousKey.Second, nextKey.Second, p);

                if (i + 1 < flattenedPoints.Count)
                {
                    widths[i + 1] = widths[i];
                }
            }

            // Compute vertices and indices.
            var      vertices        = new List <TerrainLayerVertex>(numberOfLineSegments * 2 + 2);
            var      indices         = new List <int>(numberOfLineSegments * 6); // Two triangles per line segment.
            Vector3F lastOrthonormal = Vector3F.UnitX;

            aabb = new Aabb(flattenedPoints[0], flattenedPoints[0]);
            bool isClosed = Vector3F.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);

            for (int i = 0; i < flattenedPoints.Count; i++)
            {
                Vector3F start = flattenedPoints[i];

                Vector3F previous;
                bool     isFirstPoint = (i == 0);
                if (!isFirstPoint)
                {
                    previous = flattenedPoints[i - 1];
                }
                else if (isClosed && path.SmoothEnds)
                {
                    previous = flattenedPoints[flattenedPoints.Count - 2];
                }
                else
                {
                    previous = start;
                }

                Vector3F next;
                bool     isLastPoint = (i + 1 == flattenedPoints.Count);
                if (!isLastPoint)
                {
                    next = flattenedPoints[i + 1];
                }
                else if (isClosed && path.SmoothEnds)
                {
                    next = flattenedPoints[1];
                }
                else
                {
                    next = start;
                }

                Vector3F tangent = next - previous;

                Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
                if (!orthonormal.TryNormalize())
                {
                    orthonormal = lastOrthonormal;
                }

                // Add indices to add two triangles between the current and the next vertices.
                if (!isLastPoint)
                {
                    int baseIndex = vertices.Count;

                    //  2      3
                    //   x----x
                    //   |\   |   ^
                    //   | \  |   | road
                    //   |  \ |   | direction
                    //   |   \|   |
                    //   x----x
                    //  0      1

                    indices.Add(baseIndex);
                    indices.Add(baseIndex + 1);
                    indices.Add(baseIndex + 2);

                    indices.Add(baseIndex + 1);
                    indices.Add(baseIndex + 3);
                    indices.Add(baseIndex + 2);
                }

                // Add two vertices.
                Vector3F leftVertex  = start - orthonormal * (widths[i] / 2);
                Vector3F rightVertex = start + orthonormal * (widths[i] / 2);
                vertices.Add(new TerrainLayerVertex(new Vector2(leftVertex.X, leftVertex.Z), new Vector2(0, accumulatedLengths[i])));
                vertices.Add(new TerrainLayerVertex(new Vector2(rightVertex.X, rightVertex.Z), new Vector2(1, accumulatedLengths[i])));

                // Grow AABB
                aabb.Grow(leftVertex);
                aabb.Grow(rightVertex);

                lastOrthonormal = orthonormal;

                // The flattened points list contains 2 points per line segment, which means that there
                // are duplicate intermediate points, which we skip.
                bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
                if (!isLastLineSegment)
                {
                    i++;
                }
            }

            Debug.Assert(vertices.Count == (numberOfLineSegments * 2 + 2));
            Debug.Assert(indices.Count == (numberOfLineSegments * 6));

            // The road is projected onto the terrain, therefore the computed y limits are not correct.
            // (unless the terrain was clamped to the road).
            aabb.Minimum.Y = 0;
            aabb.Maximum.Y = 0;

            // Convert to submesh.
            submesh = new Submesh
            {
                PrimitiveCount = indices.Count / 3,
                PrimitiveType  = PrimitiveType.TriangleList,
                VertexCount    = vertices.Count,
                VertexBuffer   = new VertexBuffer(graphicsDevice, TerrainLayerVertex.VertexDeclaration, vertices.Count, BufferUsage.WriteOnly),
                IndexBuffer    = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.WriteOnly)
            };
            submesh.VertexBuffer.SetData(vertices.ToArray());
            submesh.IndexBuffer.SetData(indices.ToArray());
        }
コード例 #29
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
        public void GetTangent()
        {
            Path3F path = CreatePath();
              path.PreLoop = CurveLoopType.Constant;
              path.PostLoop = CurveLoopType.Oscillate;
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 0, 0), path.GetTangent(-10)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual((new Vector3F(1, 2, 3) - new Vector3F(0, 0, 1)) / 2, path.GetTangent(10)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual((new Vector3F(1, 2, 3) - new Vector3F(0, 0, 1)) / 2, path.GetTangent(11.5f)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 0, 0), path.GetTangent(16)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 0, 0), path.GetTangent(85)));

              CatmullRomSegment3F catmullOscillate = new CatmullRomSegment3F()
              {
            Point1 = new Vector3F(10, 12, 14),
            Point2 = new Vector3F(10, 14, 8),
            Point3 = new Vector3F(20, 14, 8),
            Point4 = new Vector3F(30, 14, 8),
              };
              Assert.IsTrue(Vector3F.AreNumericallyEqual(catmullOscillate.GetTangent(0.3f) / 10.0f, path.GetTangent(43)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(-catmullOscillate.GetTangent(0.7f) / 10.0f, path.GetTangent(53)));

              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Cycle;
              Assert.IsTrue(Vector3F.AreNumericallyEqual((new Vector3F(1, 2, 3) - new Vector3F(0, 0, 1)) / 2, path.GetTangent(0)));

              path.PreLoop = CurveLoopType.Cycle;
              path.PostLoop = CurveLoopType.CycleOffset;
              Assert.IsTrue(Vector3F.AreNumericallyEqual(catmullOscillate.GetTangent(0.4f) / 10.0f, path.GetTangent(-36)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(catmullOscillate.GetTangent(0.4f) / 10.0f, path.GetTangent(4)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(catmullOscillate.GetTangent(0.3f) / 10.0f, path.GetTangent(83)));

              path.PreLoop = CurveLoopType.CycleOffset;
              path.PostLoop = CurveLoopType.Linear;
              Assert.IsTrue(Vector3F.AreNumericallyEqual(catmullOscillate.GetTangent(1f) / 10.0f, path.GetTangent(434)));

              path.PreLoop = CurveLoopType.Oscillate;
              path.PostLoop = CurveLoopType.Constant;

              path = new Path3F();
              path.Add(new PathKey3F()
              {
            Parameter = 25,
            Point = new Vector3F(6, 7, 14),
            Interpolation = SplineInterpolation.Bezier,
            TangentIn = new Vector3F(5, 6, 13),
            TangentOut = new Vector3F(7, 8, 15),
              });
              path.Add(new PathKey3F()
              {
            Parameter = 35,
            Point = new Vector3F(10, 12, 14),
            Interpolation = SplineInterpolation.Hermite,
            TangentIn = new Vector3F(1, 0, 0),
            TangentOut = new Vector3F(1, 0, 0),
              });
              path.PreLoop = CurveLoopType.Linear;
              path.PostLoop = CurveLoopType.Linear;
              float Δu = path[1].Parameter - path[0].Parameter;
              Assert.IsTrue(Vector3F.AreNumericallyEqual((new Vector3F(6, 7, 14) - new Vector3F(5, 6, 13)) * 3 / Δu, path.GetTangent(0)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(1, 0, 0) / Δu, path.GetTangent(100)));

              path[1].Parameter = 25;
              path[0].Parameter = 35;
              path.Sort();
              Δu = path[1].Parameter - path[0].Parameter;
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(1, 0, 0) / Δu, path.GetTangent(0)));
              Assert.IsTrue(Vector3F.AreNumericallyEqual((new Vector3F(7, 8, 15) - new Vector3F(6, 7, 14)) * 3 / Δu, path.GetTangent(100)));

              path.Add(new PathKey3F()
              {
            Parameter = 15,
            Point = new Vector3F(0, 0, 0),
            Interpolation = SplineInterpolation.BSpline,
              });
              path.Sort();
        }
コード例 #30
0
        public static void ClampTerrainToRoad(HeightField terrain, Path3F road,
                                              float defaultWidth, float defaultSideFalloff,
                                              int maxNumberOfIterations, float tolerance)
        {
            if (terrain == null)
            {
                throw new ArgumentNullException("terrain");
            }
            if (road == null)
            {
                throw new ArgumentNullException("road");
            }

            // Compute list of line segments. (2 points per line segment!)
            var flattenedPoints = new List <Vector3F>();

            road.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

            // Abort if path is empty.
            int numberOfLineSegments = flattenedPoints.Count / 2;

            if (numberOfLineSegments <= 0)
            {
                return;
            }

            // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
            float[] accumulatedLengths = new float[flattenedPoints.Count];
            accumulatedLengths[0] = 0;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                Vector3F previous = flattenedPoints[i - 1];
                Vector3F current  = flattenedPoints[i];
                float    length   = (current - previous).Length;

                accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
                if (i + 1 < flattenedPoints.Count)
                {
                    accumulatedLengths[i + 1] = accumulatedLengths[i];
                }
            }

            // Create a mapping between accumulatedLength and the path keys.
            // (accumulatedLength --> key)
            var pathLengthsAndKeys = new List <Pair <float, TerrainRoadPathKey> >();
            {
                int index = 0;
                foreach (var key in road)
                {
                    Vector3F position = key.Point;
                    var      roadKey  = key as TerrainRoadPathKey;
                    if (roadKey == null)
                    {
                        roadKey = new TerrainRoadPathKey
                        {
                            Point       = key.Point,
                            Width       = defaultWidth,
                            SideFalloff = defaultSideFalloff,
                        };
                    }

                    for (; index < flattenedPoints.Count; index++)
                    {
                        if (Vector3F.AreNumericallyEqual(position, flattenedPoints[index]))
                        {
                            pathLengthsAndKeys.Add(new Pair <float, TerrainRoadPathKey>(accumulatedLengths[index], roadKey));
                            break;
                        }

                        bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
                        if (!isLastLineSegment)
                        {
                            index++;
                        }
                    }

                    index++;
                }
            }

            // Create a list of interpolated road widths and side falloffs. (One entry for each entry in flattenedPoints.)
            var halfWidths       = new float[flattenedPoints.Count];
            var sideFalloffs     = new float[flattenedPoints.Count];
            int previousKeyIndex = 0;
            var previousKey      = pathLengthsAndKeys[0];
            var nextKey          = pathLengthsAndKeys[1];

            halfWidths[0]   = 0.5f * pathLengthsAndKeys[0].Second.Width;
            sideFalloffs[0] = pathLengthsAndKeys[0].Second.SideFalloff;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                if (accumulatedLengths[i] > nextKey.First)
                {
                    previousKey = nextKey;
                    previousKeyIndex++;
                    nextKey = pathLengthsAndKeys[previousKeyIndex + 1];
                }

                float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
                halfWidths[i]   = 0.5f * InterpolationHelper.Lerp(previousKey.Second.Width, nextKey.Second.Width, p);
                sideFalloffs[i] = InterpolationHelper.Lerp(previousKey.Second.SideFalloff, nextKey.Second.SideFalloff, p);

                if (i + 1 < flattenedPoints.Count)
                {
                    halfWidths[i + 1]   = halfWidths[i];
                    sideFalloffs[i + 1] = sideFalloffs[i];
                }
            }

            // Get AABB of road with the side falloff.
            Aabb aabbWithSideFalloffs;
            {
                Vector3F p = flattenedPoints[0];
                float    r = halfWidths[0] + sideFalloffs[0];
                aabbWithSideFalloffs = new Aabb(new Vector3F(p.X - r, 0, p.Z - r),
                                                new Vector3F(p.X + r, 0, p.Z + r));
                for (int i = 1; i < flattenedPoints.Count; i += 2)
                {
                    p = flattenedPoints[i];
                    r = halfWidths[i] + sideFalloffs[i];
                    aabbWithSideFalloffs.Grow(new Vector3F(p.X - r, 0, p.Z - r));
                    aabbWithSideFalloffs.Grow(new Vector3F(p.X + r, 0, p.Z + r));
                }
            }

            // Terrain properties.
            int   numberOfSamplesX = terrain.NumberOfSamplesX;
            int   numberOfSamplesZ = terrain.NumberOfSamplesZ;
            int   numberOfCellsX   = numberOfSamplesX - 1;
            int   numberOfCellsZ   = numberOfSamplesZ - 1;
            float widthX           = terrain.WidthX;
            float cellSizeX        = widthX / numberOfCellsX;
            float widthZ           = terrain.WidthZ;
            float cellSizeZ        = widthZ / numberOfCellsZ;
            float cellSizeDiagonal = (float)Math.Sqrt(cellSizeX * cellSizeX + cellSizeZ * cellSizeZ);

            bool isClosed = Vector3F.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);

            {
                // Get the line segments which of the road border.
                List <Vector4F> segments        = new List <Vector4F>(); // 2 points per segment.
                Vector3F        lastOrthonormal = Vector3F.Right;
                Vector4F        previousV1      = Vector4F.Zero;
                Vector4F        previousV2      = Vector4F.Zero;
                for (int i = 0; i < flattenedPoints.Count; i++)
                {
                    Vector3F start = flattenedPoints[i];

                    Vector3F previous;
                    bool     isFirstPoint = (i == 0);
                    if (!isFirstPoint)
                    {
                        previous = flattenedPoints[i - 1];
                    }
                    else if (isClosed && road.SmoothEnds)
                    {
                        previous = flattenedPoints[flattenedPoints.Count - 2];
                    }
                    else
                    {
                        previous = start;
                    }

                    Vector3F next;
                    bool     isLastPoint = (i + 1 == flattenedPoints.Count);
                    if (!isLastPoint)
                    {
                        next = flattenedPoints[i + 1];
                    }
                    else if (isClosed && road.SmoothEnds)
                    {
                        next = flattenedPoints[1];
                    }
                    else
                    {
                        next = start;
                    }

                    Vector3F tangent = next - previous;

                    Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
                    if (!orthonormal.TryNormalize())
                    {
                        orthonormal = lastOrthonormal;
                    }

                    // Add 2 vertices two segments for the road side border.
                    //
                    //  pV1        pV2 (previous vertices)
                    //  x           x
                    //  |           |
                    //  x           x
                    //  v1          v2 (current vertices)
                    //
                    // We store the side falloff with the vertex:
                    // Vectors are 4D. Height is y. Side falloff is w.
                    Vector4F v1 = new Vector4F(start - orthonormal * (halfWidths[i] + 0), sideFalloffs[i]);
                    Vector4F v2 = new Vector4F(start + orthonormal * (halfWidths[i] + 0), sideFalloffs[i]);

                    if (i > 0)
                    {
                        segments.Add(previousV1);
                        segments.Add(v1);
                        segments.Add(previousV2);
                        segments.Add(v2);

                        if (isLastPoint && !isClosed)
                        {
                            // A segment for the end of the road.
                            segments.Add(v1);
                            segments.Add(v2);
                        }
                    }
                    else
                    {
                        if (!isClosed)
                        {
                            // A segment for the start of the road.
                            segments.Add(v1);
                            segments.Add(v2);
                        }
                    }

                    previousV1 = v1;
                    previousV2 = v2;

                    lastOrthonormal = orthonormal;

                    // The flattened points list contains 2 points per line segment, which means that there
                    // are duplicate intermediate points, which we skip.
                    bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
                    if (!isLastLineSegment)
                    {
                        i++;
                    }
                }

                // Apply the side falloff to the terrain heights.
                // We use a padding where the road influence is 100% because we want road width to be flat
                // but that means that we also have to set some triangle vertices outside the road width to
                // full 100% road height.
                float padding = cellSizeDiagonal;
                ClampHeightsToLineSegments(terrain, aabbWithSideFalloffs, segments, padding);
            }

            // Clamp the terrain heights to the inner part of the road.
            // We create quads for the road mesh and clamp the heights to the quad triangles.
            {
                Vector3F previousV1      = Vector3F.Zero;
                Vector3F previousV2      = Vector3F.Zero;
                Vector3F lastOrthonormal = Vector3F.Right;
                for (int i = 0; i < flattenedPoints.Count; i++)
                {
                    Vector3F start = flattenedPoints[i];

                    Vector3F previous;
                    bool     isFirstPoint = (i == 0);
                    if (!isFirstPoint)
                    {
                        previous = flattenedPoints[i - 1];
                    }
                    else if (isClosed && road.SmoothEnds)
                    {
                        previous = flattenedPoints[flattenedPoints.Count - 2];
                    }
                    else
                    {
                        previous = start;
                    }

                    Vector3F next;
                    bool     isLastPoint = (i + 1 == flattenedPoints.Count);
                    if (!isLastPoint)
                    {
                        next = flattenedPoints[i + 1];
                    }
                    else if (isClosed && road.SmoothEnds)
                    {
                        next = flattenedPoints[1];
                    }
                    else
                    {
                        next = start;
                    }

                    Vector3F tangent = next - previous;

                    Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
                    if (!orthonormal.TryNormalize())
                    {
                        orthonormal = lastOrthonormal;
                    }

                    // Add 2 vertices to create a mesh like this:
                    //
                    //  pV1             pV2 (previous vertices)
                    //  x---------------x
                    //  |               |
                    //  x---------------x
                    //  v1              v2 (current vertices)
                    //
                    // Then we check all height samples against these triangles.

                    // Vectors are 4D. Height is y. Influence is w.
                    Vector3F v1 = start - orthonormal * halfWidths[i];
                    Vector3F v2 = start + orthonormal * halfWidths[i];

                    if (i > 0)
                    {
                        ClampHeightsToQuad(terrain, previousV1, previousV2, v1, v2);
                    }

                    previousV1 = v1;
                    previousV2 = v2;

                    lastOrthonormal = orthonormal;

                    // The flattened points list contains 2 points per line segment, which means that there
                    // are duplicate intermediate points, which we skip.
                    bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
                    if (!isLastLineSegment)
                    {
                        i++;
                    }
                }
            }

            terrain.Invalidate();
        }
コード例 #31
0
ファイル: Path3FTest.cs プロジェクト: Zolniu/DigitalRune
 public void GetTangentShouldReturnZeroIfPathIsEmpty()
 {
     Path3F empty = new Path3F();
       empty.Sort();
       Assert.AreEqual(Vector3F.Zero, empty.GetTangent(-0.5f));
       Assert.AreEqual(Vector3F.Zero, empty.GetTangent(0));
       Assert.AreEqual(Vector3F.Zero, empty.GetTangent(0.5f));
 }