private bool GetLeafNode(OpenBveApi.Math.Vector3 position, GridNode node, out GridLeafNode leaf) { if (node != null) { if ( position.X >= node.Rectangle.Left & position.X <= node.Rectangle.Right & position.Z >= node.Rectangle.Near & position.Z <= node.Rectangle.Far ) { if (node is GridInternalNode) { GridInternalNode intern = (GridInternalNode)node; for (int i = 0; i < intern.Children.Length; i++) { if (GetLeafNode(position, intern.Children[i], out leaf)) { return true; } } leaf = null; return false; } else if (node is GridLeafNode) { leaf = (GridLeafNode)node; return true; } else { throw new InvalidOperationException(); } } else { leaf = null; return false; } } else { leaf = null; return false; } }
/// <summary>Creates the visibility list for the specified leaf node.</summary> /// <param name="leaf">The leaf node for which to create its visibility list.</param> /// <param name="viewingDistance">The viewing distance.</param> private void CreateVisibilityList(GridLeafNode leaf, double viewingDistance) { List<GridPopulatedLeafNode> nodes = new List<GridPopulatedLeafNode>(); CreateVisibilityList(leaf, this.Root, nodes, viewingDistance); leaf.VisibleLeafNodes = nodes.ToArray(); }
/// <summary>Creates the visibility list for the specified leaf node.</summary> /// <param name="leaf">The leaf node for which to create its visibility list.</param> /// <param name="node">The node to potentially include in the visiblity list if visible.</param> /// <param name="nodes">The list of visible leaf nodes.</param> /// <param name="viewingDistance">The viewing distance.</param> private void CreateVisibilityList(GridLeafNode leaf, GridNode node, List<GridPopulatedLeafNode> nodes, double viewingDistance) { if (node != null) { bool visible; if ( leaf.BoundingRectangle.Left <= node.BoundingRectangle.Right & leaf.BoundingRectangle.Right >= node.BoundingRectangle.Left & leaf.BoundingRectangle.Near <= node.BoundingRectangle.Far & leaf.BoundingRectangle.Far >= node.BoundingRectangle.Near ) { /* * If the bounding rectangles intersect directly, the node is * definately visible from at least some point inside the leaf. * */ visible = true; } else if ( leaf.BoundingRectangle.Left - viewingDistance <= node.BoundingRectangle.Right & leaf.BoundingRectangle.Right + viewingDistance >= node.BoundingRectangle.Left & leaf.BoundingRectangle.Near - viewingDistance <= node.BoundingRectangle.Far & leaf.BoundingRectangle.Far + viewingDistance >= node.BoundingRectangle.Near ) { /* * If the leaf bounding rectangle extended by the viewing distance * in all directions intersects with the node bounding rectangle, * visibility is at least a possibility. * */ if ( leaf.BoundingRectangle.Left <= node.BoundingRectangle.Right & leaf.BoundingRectangle.Right >= node.BoundingRectangle.Left | leaf.BoundingRectangle.Near <= node.BoundingRectangle.Far & leaf.BoundingRectangle.Far >= node.BoundingRectangle.Near ) { /* * The bounding rectangles intersect, but either only on * the x-axis, or on the y-axis. This case is always visible * given that the above constraint (extension by viewing * distance) is also met. * */ visible = true; } else { /* * The bounding rectangles don't intersect on either axis. * Visibility is given if the smallest vertex-to-vertex * distance is smaller than the viewing distance. * */ if (leaf.BoundingRectangle.Right <= node.BoundingRectangle.Left) { if (leaf.BoundingRectangle.Far <= node.BoundingRectangle.Near) { double x = leaf.BoundingRectangle.Right - node.BoundingRectangle.Left; double y = leaf.BoundingRectangle.Far - node.BoundingRectangle.Near; visible = x * x + y * y <= viewingDistance * viewingDistance; } else { double x = leaf.BoundingRectangle.Right - node.BoundingRectangle.Left; double y = leaf.BoundingRectangle.Near - node.BoundingRectangle.Far; visible = x * x + y * y <= viewingDistance * viewingDistance; } } else { if (leaf.BoundingRectangle.Far <= node.BoundingRectangle.Near) { double x = leaf.BoundingRectangle.Left - node.BoundingRectangle.Right; double y = leaf.BoundingRectangle.Far - node.BoundingRectangle.Near; visible = x * x + y * y <= viewingDistance * viewingDistance; } else { double x = leaf.BoundingRectangle.Left - node.BoundingRectangle.Right; double y = leaf.BoundingRectangle.Near - node.BoundingRectangle.Far; visible = x * x + y * y <= viewingDistance * viewingDistance; } } } } else { /* * If the leaf bounding rectangle extended by the viewing distance * in all directions doesn't intersect with the node bounding rectangle, * visibility is not possible. * */ visible = false; } if (visible) { /* * The node is visible and is either added to the list of visible nodes if * a leaf node, or recursively processed for all children if an internal node. * */ if (node is GridInternalNode) { GridInternalNode intern = (GridInternalNode)node; for (int i = 0; i < intern.Children.Length; i++) { CreateVisibilityList(leaf, intern.Children[i], nodes, viewingDistance); } } else if (node is GridPopulatedLeafNode) { nodes.Add((GridPopulatedLeafNode)node); } } } }
/// <summary>Gets the leaf node for a specified position.</summary> /// <param name="position">The position.</param> /// <param name="leaf">Receives the leaf node on success.</param> /// <returns>The success of the operation.</returns> internal bool GetLeafNode(OpenBveApi.Math.Vector3 position, out GridLeafNode leaf) { return GetLeafNode(position, this.Root, out leaf); }