/// <summary> /// Creates a default instance. /// </summary> public WorldConfiguration() { LoadWholeMap = DefaultLoadWholeMap; NewPlayerSpawnPoint = new Point3D(DefaultNewPlayerSpawnX, DefaultNewPlayerSpawnY, DefaultNewPlayerSpawnZ); }
/// <summary> /// Creates a new point based on given point. /// </summary> /// <param name="point">Base point</param> public Point3D(Point3D point) { X = point.X; Y = point.Y; Z = point.Z; #if DIAG _CloneCounter++; #endif }
internal static float[] GetHighlightCoordinates(this Player player) { float[] result = new float[12]; Segment playerSegment = player.CurrentSegment; List<Box> checkBoxes = new List<Box>(playerSegment.GetBoxesSynchronized()); for (int x = playerSegment.X - 8; x <= playerSegment.X + 8; x += 8) { for (int y = playerSegment.Y - 8; y <= playerSegment.Y + 8; y += 8) { for (int z = playerSegment.Z - 8; z <= playerSegment.Z + 8; z += 8) { if (x == playerSegment.X && y == playerSegment.Y && z == playerSegment.Z) { continue; } checkBoxes.AddRange(ClientWorldManager.Instance.GetSegment(ref x, ref y, ref z).GetBoxesSynchronized()); } } } Point3D intersection = new Point3D(float.MaxValue, float.MaxValue, float.MaxValue); foreach (Box box in checkBoxes) { if (box.CenterPoint.GetDistanceSquare(player.Location) > HighlightEliminationDistance) { // too far to even consider continue; } // TODO: calculate interesection } return result; }
internal float GetBoxCenterPointDistanceSquare(Point3D point) { Point3D center = new Point3D(_Box.CenterPoint); switch (_Side) { case Sides.BackX: if (center.X - point.X > WorldHelper.HalfSizeX) { center.X -= WorldHelper.SizeX; } break; case Sides.BackZ: if (center.Z - point.Z > WorldHelper.HalfSizeX) { center.Z -= WorldHelper.SizeZ; } break; case Sides.FrontX: if (point.X - center.X > WorldHelper.HalfSizeX) { center.X += WorldHelper.SizeX; } break; case Sides.FrontZ: if (point.Z - center.Z > WorldHelper.HalfSizeX) { center.Z += WorldHelper.SizeZ; } break; default: throw new InvalidOperationException("Collision wall with invalid side: " + _Side); } return point.GetDistanceSquare(center); }
/// <summary> /// Sets this point's coordinates to the given point's coordinates and /// shift. /// </summary> /// <param name="point">Base point</param> /// <param name="shiftX">X shift</param> /// <param name="shiftY">Y shift</param> /// <param name="shiftZ">Z shift</param> public void Set(Point3D point, float shiftX, float shiftY, float shiftZ) { Set(point.X + shiftX, point.Y + shiftY, point.Z + shiftZ); }
public void TerrainDataRequest(Connection connection, int terrainMessageId, Point3D location, float rotationLeft, float rotationUp) { ClientWorldManager.Instance.LoadPlayerColumns(terrainMessageId); }
/// <summary> /// Sets this point's coordinates to the given point's coordinates. /// </summary> /// <param name="point">Base point</param> public void Set(Point3D point) { X = point.X; Y = point.Y; Z = point.Z; }
/// <summary> /// Places or removes a block. /// </summary> /// <param name="place">True to place block</param> /// <param name="x">X coordinate of the placed/removed block</param> /// <param name="y">Y coordinate of the placed/removed block</param> /// <param name="z">Z coordinate of the placed/removed block</param> /// <param name="version">Current segment version</param> /// <returns>True if block has been placed/removed</returns> public bool PlaceOrRemoveBlock(bool place, out int x, out int y, out int z, out uint version) { x = -1; y = -1; z = -1; version = 0; if (!_CanPlaceBlocks) { return false; } // check closest intersection Point3D eyeLocation = new Point3D(Location, 0.0f, _EyeHeightFromCenter, 0.0f); Vector3D line = new Vector3D(eyeLocation, NewDirection); Intersection closest = new Intersection(); List<Tuple<Box, int, int>> boxes = new List<Tuple<Box, int, int>>(); // first add current segment's boxes which have 0 shift foreach (Box box in _CurrentSegment.GetBoxesSynchronized()) { boxes.Add(Tuple.Create(box, 0, 0)); } // now add other boxes and determine possible shift foreach (Segment neighbour in _CurrentSegmentNeighbours) { int shiftX = 0; if (_CurrentSegment.X - neighbour.X > WorldHelper.HalfSizeX) { shiftX = WorldHelper.SizeX; } else if (neighbour.X - _CurrentSegment.X > WorldHelper.HalfSizeX) { shiftX = -WorldHelper.SizeX; } int shiftZ = 0; if (_CurrentSegment.Z - neighbour.Z > WorldHelper.HalfSizeZ) { shiftZ = WorldHelper.SizeZ; } else if (neighbour.Z - _CurrentSegment.Z > WorldHelper.HalfSizeZ) { shiftZ = -WorldHelper.SizeZ; } foreach (Box box in neighbour.GetBoxesSynchronized()) { boxes.Add(Tuple.Create(box, shiftX, shiftZ)); } } if (eyeLocation.Y * eyeLocation.Y < BlockInteractionRange) { boxes.Add(Tuple.Create(Box.FloorBox, 0, 0)); } int reverseShiftX = 0; int reverseShiftZ = 0; foreach (Tuple<Box, int, int> box in boxes) { Intersection intersection = box.Item1.GetIntersection(line, box.Item2, box.Item3); if (intersection.Distance < closest.Distance) { closest = intersection; reverseShiftX = -box.Item2; reverseShiftZ = -box.Item3; } } // check if there is a close intersection at all if (closest.IntersectionPoint == null || closest.Distance > BlockInteractionRange) { // not close enough or no point at all return false; } // adjust the reverse shift by accounting for reverse number truncating // when below 0 if (closest.IntersectionPoint.X < 0 && closest.IntersectionPoint.X % 1 != 0) { reverseShiftX--; } if (closest.IntersectionPoint.Z < 0 && closest.IntersectionPoint.Z % 1 != 0) { reverseShiftZ--; } // calculate cube location without the shift x = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.X)) + reverseShiftX; y = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Y)); z = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Z)) + reverseShiftZ; if (place) { // correct the location based on intersection side switch (closest.Side) { case Sides.FrontX: x--; break; case Sides.FrontY: y--; break; case Sides.FrontZ: z--; break; } } else { // correct the location based on intersection side switch (closest.Side) { case Sides.BackX: x--; break; case Sides.BackY: y--; break; case Sides.BackZ: z--; break; } } // check for floor/ceiling limits if (y < 0 || y > byte.MaxValue) { return false; } // adjust possible shift over the edge of the world after correction if (x < 0) { x += WorldHelper.SizeX; } else if (x >= WorldHelper.SizeX) { x -= WorldHelper.SizeX; } if (z < 0) { z += WorldHelper.SizeZ; } else if (z >= WorldHelper.SizeZ) { z -= WorldHelper.SizeZ; } // check if placing the block will clip into an entity if (place) { Box box = new Box(new Cube(x, y, z, 0), null); List<Entity> entities = WorldHelper.GetEntities(box.CenterPoint, BlockEntityCollisionSelectRange); bool collides = false; foreach (Entity entity in entities) { box.CheckSuffocation(entity.Location, ref entity._HalfSizeX, ref entity._HalfSizeY, ref collides); if (collides) { // at least one entity collides with the newly placed box return false; } } } // retrieve the destination segment and place or remove the block Segment destinationSegment = WorldHelper.GetSegment(x, y, z); version = destinationSegment.PlaceOrRemoveBlockAndUpdateVersion(place, x, y, z, GetSelectedMaterial()); return true; }
private void CheckSegmentChanged() { int segmentX = Convert.ToInt32(Math.Truncate(Location.X)); segmentX -= segmentX % 8; if (segmentX >= WorldHelper.SizeX) { segmentX -= WorldHelper.SizeX; } else if (segmentX < 0) { segmentX += WorldHelper.SizeX; } int segmentY = Convert.ToInt32(Math.Truncate(Location.Y)); segmentY -= segmentY % 8; int segmentZ = Convert.ToInt32(Math.Truncate(Location.Z)); segmentZ -= segmentZ % 8; if (segmentZ >= WorldHelper.SizeZ) { segmentZ -= WorldHelper.SizeZ; } else if (segmentZ < 0) { segmentZ += WorldHelper.SizeZ; } bool refreshNeighbours = false; // check if segment needs to be changed if (_CurrentSegment == null || !(_CurrentSegment.X == segmentX && _CurrentSegment.Y == segmentY && _CurrentSegment.Z == segmentZ)) { _CurrentSegment = WorldHelper.GetSegment(segmentX, segmentY, segmentZ); refreshNeighbours = true; } Point3D inBorderCheckPoint = new Point3D(Location.X - _CurrentSegment.X, Location.Y - _CurrentSegment.Y, Location.Z - _CurrentSegment.Z); bool xRefresh = (inBorderCheckPoint.X < 4 != _PreviousCheckPoint.X < 4); bool yRefresh = (inBorderCheckPoint.Y < 4 != _PreviousCheckPoint.Y < 4); bool zRefresh = (inBorderCheckPoint.Z < 4 != _PreviousCheckPoint.Z < 4); // check if neighbours are to be refreshed if (refreshNeighbours || xRefresh || yRefresh || zRefresh) { _CurrentSegmentNeighbours = WorldHelper.GetSegmentNeighboursForCollisions(_CurrentSegment, Location); } _PreviousCheckPoint = inBorderCheckPoint; // check if column area isn't changed int x = Convert.ToInt32(Math.Truncate(Location.X)); x -= x % 64; int z = Convert.ToInt32(Math.Truncate(Location.Z)); z -= z % 64; if (CurrentColumnX != x || CurrentColumnZ != z) { _CurrentColumnX = x; _CurrentColumnZ = z; if (OnColumnChanged != null) { OnColumnChanged(this, EventArgs.Empty); } } }
public void ProcessReceivedMessage(Connection connection, ref byte messageCode, ref byte[] data) { switch (messageCode) { case MessageCodes.Chat: string chatMessage = Encoding.ASCII.GetString(data, 1, data[0]); ChatMessage(connection, chatMessage); break; case MessageCodes.Disconnecting: DisconnectingNotification(connection); break; case MessageCodes.FileDataExchangeAdd: byte addExchangeType = 0; byte[] addHash = null; byte[] addFileData = null; FileDataExchangeUtils.ParseAddFileMessage(ref data, out addExchangeType, out addHash, out addFileData); AddFile(connection, addExchangeType, addHash, addFileData); break; case MessageCodes.FileDataExchangeRequest: byte requestExchangeType = 0; byte[] requestHash = null; FileDataExchangeUtils.ParseCheckFileExistRequest(ref data, out requestExchangeType, out requestHash); CheckFileExistRequest(connection, requestExchangeType, requestHash); break; case MessageCodes.FileDataExchangeResponse: byte responseExchangeType = 0; byte[] responseHash = null; bool responseExists = false; FileDataExchangeUtils.ParseCheckFileExistResponse(ref data, out responseExchangeType, out responseHash, out responseExists); CheckFileExistResponse(connection, responseExchangeType, responseHash, responseExists); break; case MessageCodes.FileDataRequest: byte fileExchangeType = 0; byte[] fileHash = null; FileDataExchangeUtils.ParseFileRequest(ref data, out fileExchangeType, out fileHash); RequestFile(connection, fileExchangeType, fileHash); break; case MessageCodes.GeneralNo: break; case MessageCodes.GeneralYes: break; case MessageCodes.Login: int offset = 0; int nameLength = data[offset]; offset++; string name = Encoding.ASCII.GetString(data, offset, nameLength); offset += nameLength; int passwordLength = data[offset]; offset++; string password = Encoding.ASCII.GetString(data, offset, passwordLength); offset += passwordLength; int versionLength = data[offset]; offset++; string version = Encoding.ASCII.GetString(data, offset, versionLength); offset += versionLength; byte[] skinHash = new byte[16]; for (int i = 0; i < 16; i++) { skinHash[i] = data[offset + i]; } LoginRequest(connection, name, password, version, skinHash); break; case MessageCodes.Moved: Point3D movedLocation = new Point3D(); movedLocation.InitializeFromByteArray(ref data, 0); float rotationLeft = BitConverter.ToSingle(data, Point3D.SerializedSize); float rotationUp = BitConverter.ToSingle(data, Point3D.SerializedSize + 4); PlayerMovedNotification(connection, movedLocation, rotationLeft, rotationUp); break; case MessageCodes.Moving: break; //case MessageCodes.MultipartCompressed: // connection.ProcessMultipartMessage(ref data); // break; case MessageCodes.PlaceOrRemoveCube: bool place = (data[0] > 0); Point3D placeLocation = new Point3D(); placeLocation.InitializeFromByteArray(ref data, 1); float placeRotationLeft = BitConverter.ToSingle(data, Point3D.SerializedSize + 1); float placeRotationUp = BitConverter.ToSingle(data, Point3D.SerializedSize + 5); ushort placeMaterialId = BitConverter.ToUInt16(data, Point3D.SerializedSize + 9); PlaceOrRemoveCubeNotification(connection, place, placeLocation, placeRotationLeft, placeRotationUp, placeMaterialId); break; case MessageCodes.Terrain: int terrainMessageId = BitConverter.ToInt32(data, 0); Point3D terrainLocation = new Point3D(); terrainLocation.InitializeFromByteArray(ref data, 4); float terrainRotationLeft = BitConverter.ToSingle(data, Point3D.SerializedSize + 4); float terrainRotationUp = BitConverter.ToSingle(data, Point3D.SerializedSize + 8); TerrainDataRequest(connection, terrainMessageId, terrainLocation, terrainRotationLeft, terrainRotationUp); break; } }
/// <summary> /// Creates an intersection from given parameters. /// </summary> /// <param name="distance">Distance to intersection</param> /// <param name="intersectionPoint">Point of intersection</param> /// <param name="side">Side of intersection</param> public Intersection(float distance, Point3D intersectionPoint, int side) { Distance = distance; IntersectionPoint = intersectionPoint; Side = side; }
/// <summary> /// Gets whether a given point is inside a triangle /// </summary> /// <param name="p">Point</param> /// <param name="triangle">Triangle defined by 3 points</param> /// <returns>True if the point is inside given triangle</returns> public static bool IsPointInTriangle(Point3D p, Tuple<Point3D, Point3D, Point3D> triangle) { // taken from http://www.blackpawn.com/texts/pointinpoly/default.html // Compute vectors Point3D a = triangle.Item1; Point3D b = triangle.Item2; Point3D c = triangle.Item3; Point3D v0 = c - a; Point3D v1 = b - a; Point3D v2 = p - a; // Compute dot products float dot00 = v0.DotProduct(v0); float dot01 = v0.DotProduct(v1); float dot02 = v0.DotProduct(v2); float dot11 = v1.DotProduct(v1); float dot12 = v1.DotProduct(v2); // Compute barycentric coordinates double invDenom = 1F / (dot00 * dot11 - dot01 * dot01); double u = (dot11 * dot02 - dot01 * dot12) * invDenom; double v = (dot00 * dot12 - dot01 * dot02) * invDenom; // Check if point is in triangle return (u >= 0) && (v >= 0) && (u + v <= 1); }
/// <summary> /// Gets a dot product from this and given vector. /// </summary> /// <param name="other">Other vector</param> /// <returns>Dot product</returns> public float DotProduct(Point3D other) { return X * other.X + Y * other.Y + Z * other.Z; }
/// <summary> /// Gets a cross product between two points. /// </summary> /// <param name="point1">Vector 1</param> /// <param name="point2">Vector 2</param> /// <returns>Cross product</returns> public static Point3D CrossProduct(Point3D point1, Point3D point2) { return new Point3D(point1.Y * point2.Z - point1.Z * point2.Y, point1.Z * point2.X - point1.X * point2.Z, point1.X * point2.Y - point1.Y * point2.X); }
/// <summary> /// Gets an angle between two vectors. /// </summary> /// <param name="origin">Origin</param> /// <param name="vector1">Vector 1</param> /// <param name="vector2">Vector 2</param> /// <returns>Angle between two vectors which is not divided by /// Math.PI</returns> public static double GetAngleRadians(Point3D origin, Point3D vector1, Point3D vector2) { // this is extremely unlikely to happen so lets just ignore this case //if ((vector1.X == 0.0f && vector1.Y == 0.0f && vector1.Z == 0.0f) || // (vector2.X == 0.0f && vector2.Y == 0.0f && vector2.Z == 0.0f)) //{ // // unable to calculate so return -1 // return -1; //} Point3D a = (vector1 - origin); a.Normalize(); Point3D b = (vector2 - origin); b.Normalize(); #if DIAG _AngleCounter++; #endif return Math.Acos(a.X * b.X + a.Y * b.Y + a.Z * b.Z); }
/// <summary> /// Creates a new point based on given point and coordinate shifts. /// </summary> /// <param name="point">Base point</param> /// <param name="shiftX">X coordinate shift</param> /// <param name="shiftY">Y coordinate shift</param> /// <param name="shiftZ">Z coordinate shift</param> public Point3D(Point3D point, float shiftX, float shiftY, float shiftZ) : this(point) { X += shiftX; Y += shiftY; Z += shiftZ; #if DIAG _CloneCounter++; #endif }
public void PlayerMovedNotification(Connection connection, Point3D location, float rotationLeft, float rotationUp) { // empty }
/// <summary> /// Creates a vector using given points. /// </summary> /// <param name="point1">First point</param> /// <param name="point2">Second point</param> public Vector3D(Point3D point1, Point3D point2) { Point1 = point1; Point2 = point2; }
public void PlaceOrRemoveCubeNotification(Connection connection, bool place, Point3D location, float rotationLeft, float rotationUp, ushort materialId) { //Console.WriteLine("> PlaceOrRemoveCubeNotification"); // adjust player's location and heading PlayerMovedNotification(connection, location, rotationLeft, rotationUp); // set material connection.Player.SelectedMaterial = materialId; int x = -1; int y = -1; int z = -1; uint version = 0; if (!connection.Player.PlaceOrRemoveBlock(place, out x, out y, out z, out version)) { // ignore return; } // distribute info about changed terrain Segment segment = ServerWorldManager.Instance.GetSegmentBasedOnInsidePoint(x, y, z); foreach (Connection other in ServerManager.Instance.GetAuthenticatedPlayers()) { if (ServerWorldManager.Instance.IsPlayersArea(other.Player, segment.Area.Key)) { ServerManager.Instance.ServerToClientProvider.PlaceOrRemoveCubeNotification(other, place, segment, x, y, z, connection.Player.GetSelectedMaterial(), version); } } }
/// <summary> /// Gets the distance between this and given point. /// </summary> /// <param name="point2">Second point</param> /// <returns>Distance between this and given point</returns> public double GetDistance(Point3D point2) { #if DIAG _DistanceCounter++; #endif return Math.Sqrt(Square(X - point2.X) + Square(Y - point2.Y) + Square(Z - point2.Z)); }
public void PlayerMovedNotification(Connection connection, Point3D location, float rotationLeft, float rotationUp) { //Console.WriteLine("> PlayerMovedNotification: Pos {0}, L {1:0.0}, U {2:0.0}", location, rotationLeft, rotationUp); connection.Player.SetLocation(location, rotationLeft, rotationUp, true, Environment.TickCount); foreach (Connection other in ServerManager.Instance.GetAuthenticatedPlayers(connection.Player.ID)) { ServerManager.Instance.ServerToClientProvider.EntityMovedNotification(other, connection.Player.ID, location, rotationLeft, rotationUp, connection.Player.LastLocationUpdate); } }
/// <summary> /// Gets the distance square between this and given point. /// </summary> /// <param name="other">Other point</param> /// <returns>Distance square between this and given point</returns> public float GetDistanceSquare(Point3D other) { #if DIAG _DistanceCounter++; #endif return Square(X - other.X) + Square(Y - other.Y) + Square(Z - other.Z); }
public void TerrainDataRequest(Connection connection, int terrainMessageId, Point3D location, float rotationLeft, float rotationUp) { Console.WriteLine("> TerrainDataRequest: {0}", terrainMessageId); PlayerMovedNotification(connection, location, rotationLeft, rotationUp); ServerWorldManager.Instance.LoadClientColumns(terrainMessageId, connection.Player); }
public void PlaceOrRemoveCubeNotification(Connection connection, bool place, Point3D location, float rotationLeft, float rotationUp, ushort materialId) { ClientWorldManager.Instance.Player.PlaceOrRemoveBlock(place); }
/// <summary> /// Handles the entity movement in the world. /// </summary> /// <returns>True if moved</returns> public bool HandleMovement() { bool moved = false; if (!_CanMove) { return moved; } // calculate movement _CurrentTime = Environment.TickCount; if (MoveX != 0 || MoveY != 0 || MoveZ != 0) { moved = true; if (_CurrentSegment == null) { CheckSegmentChanged(); } double distance = (_CurrentTime - _LastMoveTime) * Speed.EntityBaseSpeed; Point3D move = new Point3D(MoveX * distance, MoveY * distance, MoveZ * distance); move.Rotate(ref _RotationLeft, ref _ZeroUpDownRotation); Point3D original = new Point3D(Location); Location += move; // check collisions and adjust location if needed Vector3D moveVector = new Vector3D(original, Location); List<Box> boxesForCheck = new List<Box>(_CurrentSegment.GetBoxesSynchronized()); foreach (Segment neighbour in _CurrentSegmentNeighbours) { if (neighbour != null) { boxesForCheck.AddRange(neighbour.GetBoxesSynchronized()); } } // floor/ceiling collisions _Falling = true; foreach (Box box in boxesForCheck) { Location.Y += box.CheckFloorCeilingCollisions(moveVector, ref _HalfSizeX, ref _HalfSizeY, ref _Falling); } // world floor/ceiling check if (Location.Y - _HalfSizeY < 0.0f) { Location.Y = _HalfSizeY; } else if (Location.Y + _HalfSizeY > 255.0f) { Location.Y = 255.0f - _HalfSizeY; } // assemble collision walls List<CollisionWall> walls = new List<CollisionWall>(_CurrentSegment.GetCollisionWalls()); foreach (Segment neighbour in _CurrentSegmentNeighbours) { if (neighbour != null) { walls.AddRange(neighbour.GetCollisionWalls()); } } // walls.RemoveAll(w => w.GetBoxCenterPointDistanceSquare(Location) > 4.0f); // check wall collisions float[] xData = new float[] { 512.0f, 0.0f }; float[] zData = new float[] { 512.0f, 0.0f }; foreach (CollisionWall wall in walls) { if (wall.Side == Sides.FrontX || wall.Side == Sides.BackX) { wall.CheckWallCollisions(moveVector, ref _HalfSizeX, ref _HalfSizeY, ref xData); } if (wall.Side == Sides.FrontZ || wall.Side == Sides.BackZ) { wall.CheckWallCollisions(moveVector, ref _HalfSizeX, ref _HalfSizeY, ref zData); } } // apply shift based on wall collisons Location.X += xData[1]; Location.Z += zData[1]; // check suffocation _Suffocating = false; foreach (Box box in boxesForCheck) { box.CheckSuffocation(Location, ref _HalfSizeX, ref _HalfSizeY, ref _Suffocating); } // check move over map edge if (Location.X < 0) { Location.X += WorldHelper.SizeX; } else if (Location.X >= WorldHelper.SizeX) { Location.X -= WorldHelper.SizeX; } if (Location.Z < 0) { Location.Z += WorldHelper.SizeZ; } else if (Location.Z >= WorldHelper.SizeZ) { Location.Z -= WorldHelper.SizeZ; } // check if segment changed CheckSegmentChanged(); } // calculate new direction moved |= HandleRotation(); // update last moved time _LastMoveTime = _CurrentTime; return moved; }
/// <summary> /// Rotates the point around given origin by given angles. /// </summary> /// <param name="origin">Origin point to rotate around</param> /// <param name="leftRightAngle">Left/right rotation angle</param> /// <param name="upDownAngle">Up/down rotation angle</param> public void Rotate(Point3D origin, float leftRightAngle, float upDownAngle) { Rotate(origin, ref leftRightAngle, ref upDownAngle); }
/// <summary> /// Set the entity location and direction. /// </summary> /// <param name="location">Current location</param> /// <param name="rotationLeft">Rotation left</param> /// <param name="rotationUp">Rotation up</param> /// <param name="handleMovement">Determines whether movement should be /// handled</param> /// <param name="movedTime">Moved time</param> public void SetLocation(Point3D location, float rotationLeft, float rotationUp, bool handleMovement, int movedTime) { if (movedTime < LastLocationUpdate) { return; } LastLocationUpdate = movedTime; Location = location; NewRotationLeft = rotationLeft; NewRotationUp = rotationUp; if (handleMovement) { CheckSegmentChanged(); HandleMovement(); } else { HandleRotation(); } }
/// <summary> /// Rotates the point around given origin by given angles. /// </summary> /// <param name="origin">Origin point to rotate around</param> /// <param name="leftRightAngle">Left/right rotation angle</param> /// <param name="upDownAngle">Up/down rotation angle</param> public void Rotate(Point3D origin, ref float leftRightAngle, ref float upDownAngle) { #if DIAG _RotationCounter++; #endif double x = (X -= origin.X); double y = (Y -= origin.Y); double z = (Z -= origin.Z); double upDownDegrees = upDownAngle * _Pi; double upDownCosDegrees = Math.Cos(upDownDegrees); double upDownSinDegrees = Math.Sin(upDownDegrees); double leftRightDegrees = leftRightAngle * _Pi; double leftRightCosDegrees = Math.Cos(leftRightDegrees); double leftRightSinDegrees = Math.Sin(leftRightDegrees); y = (Y * upDownCosDegrees) + (Z * upDownSinDegrees); z = (Y * -upDownSinDegrees) + (Z * upDownCosDegrees); x = (X * leftRightCosDegrees) + (z * leftRightSinDegrees); z = (X * -leftRightSinDegrees) + (z * leftRightCosDegrees); X = Convert.ToSingle(x) + origin.X; Y = Convert.ToSingle(y) + origin.Y; Z = Convert.ToSingle(z) + origin.Z; }
private void InitializeFromByteArray(ref byte[] data) { // initialize the base part Location = new Point3D(); _EntityType = data[OffsetEntityType]; _ID = BitConverter.ToUInt16(data, OffsetID); Location.InitializeFromByteArray(ref data, OffsetLocation); _RotationLeft = BitConverter.ToSingle(data, OffsetRotationLeft); _NewRotationLeft = _RotationLeft; _RotationUp = BitConverter.ToSingle(data, OffsetRotationUp); _NewRotationUp = _RotationUp; int x = Convert.ToInt32(Location.X); int z = Convert.ToInt32(Location.Z); _CurrentColumnX = x - x % 64; _CurrentColumnZ = z - z % 64; lock (_NextIdLock) { if (_NextId <= ID) { _NextIdLock = ID + 1; } } // initialize the deriving part InitializeFromByteArray(ref data, SerializedSize); }
public void GetRectangleIntersectionTest() { Point3D pl1 = new Point3D(-5, 0, -5); Point3D pl2 = new Point3D(5, 0, -5); Point3D pl3 = new Point3D(5, 0, 5); Point3D pl4 = new Point3D(-5, 0, 5); var pl = Tuple.Create(pl1, pl2, pl3, pl4); // one intersection at [-4; 0; 4] Point3D u1 = new Point3D(-4, 2, 4); Point3D u2 = new Point3D(-4, -2, 4); var u = new Vector3D(u1, u2); var result = Point3D.GetRectangleIntersection(pl, u); Assert.IsTrue(result.Item1 == 1); Assert.AreEqual<Point3D>(result.Item2, new Point3D(-4, 0, 4)); // one intersection at [-4; 0; 4] u1 = new Point3D(-5, 2, 5); u2 = new Point3D(-3, -2, 3); u = new Vector3D(u1, u2); result = Point3D.GetRectangleIntersection(pl, u); Assert.IsTrue(result.Item1 == 1); Assert.AreEqual<Point3D>(result.Item2, new Point3D(-4, 0, 4)); // one intersection at [0; 0; 0] u1 = new Point3D(0, 2, 0); u2 = new Point3D(0, -2, 0); u = new Vector3D(u1, u2); result = Point3D.GetRectangleIntersection(pl, u); Assert.IsTrue(result.Item1 == 1); Assert.AreEqual<Point3D>(result.Item2, new Point3D(0, 0, 0)); // no intersection u1 = new Point3D(-4, -1, 4); u2 = new Point3D(-4, -2, 4); u = new Vector3D(u1, u2); result = Point3D.GetRectangleIntersection(pl, u); Assert.IsTrue(result.Item1 == 0); Assert.IsNull(result.Item2); // no intersection u1 = new Point3D(-5.5, 2, 5); u2 = new Point3D(-5, -2, 5); u = new Vector3D(u1, u2); result = Point3D.GetRectangleIntersection(pl, u); Assert.IsTrue(result.Item1 == 0); Assert.IsNull(result.Item2); // line is in the plane u1 = new Point3D(4, 0, 4); u2 = new Point3D(3, 0, 3); u = new Vector3D(u1, u2); result = Point3D.GetRectangleIntersection(pl, u); Assert.IsTrue(result.Item1 == 2); Assert.IsNull(result.Item2); }