/// <summary> /// Returns the cell, and a rotator for a tile placed near the generator /// A rotator takes vectors in the tile local space, and returns them in generator local space. /// It's always an distance presering transform (so it's always one of the symmetries of a cube). /// /// NB: The cell returned corresponds to offset (0,0,0). The tile may not actually occupy that offset. /// </summary> internal static bool GetCell( Transform transform, Vector3 center, Vector3 tileSize, Vector3Int size, TesseraTile tile, Matrix4x4 tileLocalToWorldMatrix, out Vector3Int cell, out MatrixInt3x3 rotator) { var m = transform.worldToLocalMatrix * tileLocalToWorldMatrix; Vector3Int Rotate(Vector3Int v) { var v1 = m.MultiplyVector(v); var v2 = new Vector3Int((int)Math.Round(v1.x), (int)Math.Round(v1.y), (int)Math.Round(v1.z)); return(v2); } // True if v is a unit vector along an axis bool Ok(Vector3Int v) { return(Math.Abs(v.x) + Math.Abs(v.y) + Math.Abs(v.z) == 1); } var rotatedRight = Rotate(Vector3Int.right); var rotatedUp = Rotate(Vector3Int.up); var rotatedForward = Rotate(new Vector3Int(0, 0, 1)); if (Ok(rotatedRight) && Ok(rotatedUp) && Ok(rotatedForward)) { var localPos = m.MultiplyPoint(tile.center); var min = center - Vector3.Scale(size - Vector3Int.one, tileSize) / 2.0f; localPos -= min; var x = (int)Mathf.Round(localPos.x / tileSize.x); var y = (int)Mathf.Round(localPos.y / tileSize.y); var z = (int)Mathf.Round(localPos.z / tileSize.z); cell = new Vector3Int(x, y, z); rotator = new MatrixInt3x3 { col1 = rotatedRight, col2 = rotatedUp, col3 = rotatedForward, }; return(true); } else { cell = default; rotator = default; return(false); } }
/// <summary> /// Returns the cell, and a rotator for a tile placed near the generator /// A rotator takes vectors in the tile local space, and returns them in generator local space. /// It's always an distance presering transform (so it's always one of the symmetries of a cube). /// /// NB: The cell returned corresponds to offset (0,0,0). The tile may not actually occupy that offset. /// </summary> internal bool GetCell( TesseraTile tile, Matrix4x4 tileLocalToWorldMatrix, out Vector3Int cell, out MatrixInt3x3 rotator) { return(GeometryUtils.GetCell( transform, center, tileSize, size, tile, tileLocalToWorldMatrix, out cell, out rotator)); }
/// <summary> /// Given a FaceDetails on given face of the cube, /// rotates the cube, and returns the new face and correctly oriented FaceDetails /// </summary> internal static (FaceDir, FaceDetails) ApplyRotator(FaceDir faceDir, FaceDetails faceDetails, MatrixInt3x3 rotator) { var rotatedFaceDirForward = rotator.Multiply(faceDir.Forward()); var rotatedFaceDirUp = rotator.Multiply(faceDir.Up()); var rotatedFaceDirRight = rotator.Multiply(Vector3.Cross(faceDir.Forward(), faceDir.Up())); var rotatedFaceDir = FromNormal(rotatedFaceDirForward); var trueUp = rotatedFaceDir.Up(); var trueForward = rotatedFaceDirForward; // = rotatedFaceDir.Forward(); var trueRight = Vector3.Cross(trueForward, trueUp); // Find the rotation that will map rotatedFaceDirUp to trueUp // and rotatedFaceDirRight to trueRight var dot = Vector3.Dot(rotatedFaceDirUp, trueUp); var cross = Vector3.Dot(rotatedFaceDirUp, trueRight); Rotation faceRot; if (dot == 1) { faceRot = new Rotation(); } else if (dot == -1) { faceRot = new Rotation(180); } else if (cross == 1) { faceRot = new Rotation(270); } else if (cross == -1) { faceRot = new Rotation(90); } else { throw new Exception(); } if (Vector3.Dot(Vector3.Cross(rotatedFaceDirForward, rotatedFaceDirUp), rotatedFaceDirRight) < 0) { faceRot = new Rotation(360 - faceRot.RotateCw, true); } var rotatedFaceDetails = faceDetails.RotateBy(faceRot); return(rotatedFaceDir, rotatedFaceDetails); }