Beispiel #1
0
 // instance functions
 /// <summary>Adds a new instance of a static object to the grid.</summary>
 /// <param name="libraryIndex">The index to a library object.</param>
 /// <param name="position">The absolute world position of the object.</param>
 /// <param name="orientation">The absolute world orientation of the object.</param>
 internal void Add(int libraryIndex, OpenBveApi.Math.Vector3 position, OpenBveApi.Math.Orientation3 orientation)
 {
     if (this.Root == null) {
         // the root node does not exist yet
         OpenBveApi.Math.Vector3 gridPosition = new OpenBveApi.Math.Vector3(0.0, position.Y, 0.0);
         GridPopulatedLeafNode leaf = new GridPopulatedLeafNode(
             null,
             new GridBounds(
                 position.X - 0.5 * this.SideLength,
                 position.X + 0.5 * this.SideLength,
                 position.Z - 0.5 * this.SideLength,
                 position.Z + 0.5 * this.SideLength
             ),
             new StaticOpaqueObject(libraryIndex, gridPosition, orientation)
         );
         leaf.UpdateBoundingRectangle(libraryIndex, gridPosition, orientation);
         this.Root = leaf;
     } else {
         // the root node exists
         while (true) {
             if (position.X >= this.Root.Rectangle.Left & position.X <= this.Root.Rectangle.Right & position.Z >= this.Root.Rectangle.Near & position.Z <= this.Root.Rectangle.Far) {
                 // the position is within the bounds of the root node
                 GridNode node = this.Root;
                 double left = this.Root.Rectangle.Left;
                 double right = this.Root.Rectangle.Right;
                 double near = this.Root.Rectangle.Near;
                 double far = this.Root.Rectangle.Far;
                 while (true) {
                     if (node is GridPopulatedLeafNode) {
                         // populated leaf node
                         OpenBveApi.Math.Vector3 gridPosition = new OpenBveApi.Math.Vector3(
                             position.X - 0.5 * (left + right),
                             position.Y,
                             position.Z - 0.5 * (near + far)
                         );
                         GridPopulatedLeafNode leaf = (GridPopulatedLeafNode)node;
                         if (leaf.StaticOpaqueObjectCount == leaf.StaticOpaqueObjects.Length) {
                             Array.Resize<StaticOpaqueObject>(ref leaf.StaticOpaqueObjects, leaf.StaticOpaqueObjects.Length << 1);
                         }
                         leaf.VisibleLeafNodes = null;
                         leaf.StaticOpaqueObjects[leaf.StaticOpaqueObjectCount] = new StaticOpaqueObject(libraryIndex, gridPosition, orientation);
                         leaf.StaticOpaqueObjectCount++;
                         leaf.UpdateBoundingRectangle(libraryIndex, gridPosition, orientation);
                         break;
                     } else if (node is GridInternalNode) {
                         // internal node
                         GridInternalNode intern = (GridInternalNode)node;
                         int index;
                         double centerX = 0.5 * (left + right);
                         double centerZ = 0.5 * (near + far);
                         if (position.Z <= centerZ) {
                             if (position.X <= centerX) {
                                 index = 0;
                                 right = centerX;
                                 far = centerZ;
                             } else {
                                 index = 1;
                                 left = centerX;
                                 far = centerZ;
                             }
                         } else {
                             if (position.X <= centerX) {
                                 index = 2;
                                 right = centerX;
                                 near = centerZ;
                             } else {
                                 index = 3;
                                 left = centerX;
                                 near = centerZ;
                             }
                         }
                         if (intern.Children[index] is GridUnpopulatedLeafNode) {
                             double sideLength = 0.5 * (right - left + far - near);
                             const double toleranceFactor = 1.01;
                             if (sideLength < toleranceFactor * this.SideLength) {
                                 // create populated leaf child
                                 GridPopulatedLeafNode child = new GridPopulatedLeafNode(
                                     intern,
                                     new GridBounds(left, right, near, far),
                                     null
                                 );
                                 child.BoundingRectangle = GridBounds.Uninitialized;
                                 intern.Children[index] = child;
                                 node = child;
                             } else {
                                 // create internal child
                                 GridInternalNode child = new GridInternalNode(
                                     intern,
                                     new GridBounds(left, right, near, far),
                                     new GridNode[] { null, null, null, null }
                                 );
                                 child.Children[0] = new GridUnpopulatedLeafNode(child, new GridBounds(left, 0.5 * (left + right), near, 0.5 * (near + far)));
                                 child.Children[1] = new GridUnpopulatedLeafNode(child, new GridBounds(0.5 * (left + right), right, near, 0.5 * (near + far)));
                                 child.Children[2] = new GridUnpopulatedLeafNode(child, new GridBounds(left, 0.5 * (left + right), 0.5 * (near + far), far));
                                 child.Children[3] = new GridUnpopulatedLeafNode(child, new GridBounds(0.5 * (left + right), right, 0.5 * (near + far), far));
                                 intern.Children[index] = child;
                                 node = child;
                             }
                         } else {
                             // go to child
                             node = intern.Children[index];
                         }
                     } else {
                         throw new InvalidOperationException();
                     }
                 }
                 break;
             } else {
                 // the position is outside the bounds of the root node
                 if (position.Z <= 0.5 * (this.Root.Rectangle.Near + this.Root.Rectangle.Far)) {
                     if (position.X <= 0.5 * (this.Root.Rectangle.Left + this.Root.Rectangle.Right)) {
                         // expand toward near-left
                         GridInternalNode intern = new GridInternalNode(
                             null,
                             new GridBounds(
                                 2.0 * this.Root.Rectangle.Left - this.Root.Rectangle.Right,
                                 this.Root.Rectangle.Right,
                                 2.0 * this.Root.Rectangle.Near - this.Root.Rectangle.Far,
                                 this.Root.Rectangle.Far
                             ),
                             new GridNode[] { null, null, null, this.Root }
                         );
                         this.Root.Parent = intern;
                         intern.Children[0] = new GridUnpopulatedLeafNode(intern, new GridBounds(intern.Rectangle.Left, 0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Near, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far)));
                         intern.Children[1] = new GridUnpopulatedLeafNode(intern, new GridBounds(0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Right, intern.Rectangle.Near, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far)));
                         intern.Children[2] = new GridUnpopulatedLeafNode(intern, new GridBounds(intern.Rectangle.Left, 0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far), intern.Rectangle.Far));
                         intern.UpdateBoundingRectangle();
                         this.Root = intern;
                     } else {
                         // expand toward near-right
                         GridInternalNode intern = new GridInternalNode(
                             null,
                             new GridBounds(
                                 this.Root.Rectangle.Left,
                                 2.0 * this.Root.Rectangle.Right - this.Root.Rectangle.Left,
                                 2.0 * this.Root.Rectangle.Near - this.Root.Rectangle.Far,
                                 this.Root.Rectangle.Far
                             ),
                             new GridNode[] { null, null, this.Root, null }
                         );
                         this.Root.Parent = intern;
                         intern.Children[0] = new GridUnpopulatedLeafNode(intern, new GridBounds(intern.Rectangle.Left, 0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Near, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far)));
                         intern.Children[1] = new GridUnpopulatedLeafNode(intern, new GridBounds(0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Right, intern.Rectangle.Near, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far)));
                         intern.Children[3] = new GridUnpopulatedLeafNode(intern, new GridBounds(0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Right, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far), intern.Rectangle.Far));
                         intern.UpdateBoundingRectangle();
                         this.Root = intern;
                     }
                 } else {
                     if (position.X <= 0.5 * (this.Root.Rectangle.Left + this.Root.Rectangle.Right)) {
                         // expand toward far-left
                         GridInternalNode intern = new GridInternalNode(
                             null,
                             new GridBounds(
                                 2.0 * this.Root.Rectangle.Left - this.Root.Rectangle.Right,
                                 this.Root.Rectangle.Right,
                                 this.Root.Rectangle.Near,
                                 2.0 * this.Root.Rectangle.Far - this.Root.Rectangle.Near
                             ),
                             new GridNode[] { null, this.Root, null, null }
                         );
                         this.Root.Parent = intern;
                         intern.Children[0] = new GridUnpopulatedLeafNode(intern, new GridBounds(intern.Rectangle.Left, 0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Near, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far)));
                         intern.Children[2] = new GridUnpopulatedLeafNode(intern, new GridBounds(intern.Rectangle.Left, 0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far), intern.Rectangle.Far));
                         intern.Children[3] = new GridUnpopulatedLeafNode(intern, new GridBounds(0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Right, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far), intern.Rectangle.Far));
                         intern.UpdateBoundingRectangle();
                         this.Root = intern;
                     } else {
                         // expand toward far-right
                         GridInternalNode intern = new GridInternalNode(
                             null,
                             new GridBounds(
                                 this.Root.Rectangle.Left,
                                 2.0 * this.Root.Rectangle.Right - this.Root.Rectangle.Left,
                                 this.Root.Rectangle.Near,
                                 2.0 * this.Root.Rectangle.Far - this.Root.Rectangle.Near
                             ),
                             new GridNode[] { this.Root, null, null, null }
                         );
                         this.Root.Parent = intern;
                         intern.Children[1] = new GridUnpopulatedLeafNode(intern, new GridBounds(0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Right, intern.Rectangle.Near, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far)));
                         intern.Children[2] = new GridUnpopulatedLeafNode(intern, new GridBounds(intern.Rectangle.Left, 0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far), intern.Rectangle.Far));
                         intern.Children[3] = new GridUnpopulatedLeafNode(intern, new GridBounds(0.5 * (intern.Rectangle.Left + intern.Rectangle.Right), intern.Rectangle.Right, 0.5 * (intern.Rectangle.Near + intern.Rectangle.Far), intern.Rectangle.Far));
                         intern.UpdateBoundingRectangle();
                         this.Root = intern;
                     }
                 }
             }
         }
     }
 }
Beispiel #2
0
 // constructors
 internal GridPopulatedLeafNode(GridInternalNode parent, GridBounds rectangle, StaticOpaqueObject initialStaticOpaqueObject)
 {
     this.Parent = parent;
     this.Rectangle = rectangle;
     this.BoundingRectangle = GridBounds.Uninitialized;
     this.VisibleLeafNodes = null;
     if (initialStaticOpaqueObject != null) {
         this.StaticOpaqueObjects = new StaticOpaqueObject[] { initialStaticOpaqueObject };
         this.StaticOpaqueObjectCount = 1;
     } else {
         this.StaticOpaqueObjects = new StaticOpaqueObject[] { null };
         this.StaticOpaqueObjectCount = 0;
     }
     this.DisplayList = new DisplayList();
     this.TransparentFaces = new object[1];
     this.TransparentFaceCount = 0;
 }
Beispiel #3
0
 // constructors
 internal GridUnpopulatedLeafNode(GridInternalNode parent, GridBounds rectangle)
 {
     this.Parent = parent;
     this.Rectangle = rectangle;
     this.BoundingRectangle = GridBounds.Uninitialized;
     this.VisibleLeafNodes = null;
 }
Beispiel #4
0
 // constructors
 internal GridInternalNode(GridInternalNode parent, GridBounds rectangle, GridNode[] children)
 {
     this.Parent = parent;
     this.Rectangle = rectangle;
     this.BoundingRectangle = GridBounds.Uninitialized;
     this.Children = children;
 }