public static Matrix <float> CalculateRotationMatrix(Vector <float> rotationVector) { var rad = rotationVector.Storage.AsArray().Select(x => (float)Trig.DegreeToRadian(x)).ToArray(); var radianRotation = new DenseVector(rad); float cosX = (float)Math.Cos(radianRotation[0]); float sinX = (float)Math.Sin(radianRotation[0]); float cosY = (float)Math.Cos(radianRotation[1]); float sinY = (float)Math.Sin(radianRotation[1]); float cosZ = (float)Math.Cos(radianRotation[2]); float sinZ = (float)Math.Sin(radianRotation[2]); Matrix xRotationMatrix = new DenseMatrix(4, 4); xRotationMatrix.SetRow(0, new [] { 1f, 0f, 0f, 0f }); xRotationMatrix.SetRow(1, new [] { 0f, cosX, -sinX, 0f }); xRotationMatrix.SetRow(2, new [] { 0f, sinX, cosX, 0f }); xRotationMatrix.SetRow(3, new [] { 0f, 0f, 0f, 1f }); Matrix yRotationMatrix = new DenseMatrix(4, 4); yRotationMatrix.SetRow(0, new[] { cosY, 0f, sinY, 0f }); yRotationMatrix.SetRow(1, new[] { 0f, 1f, 0f, 0f }); yRotationMatrix.SetRow(2, new[] { -sinY, 0f, cosY, 0f }); yRotationMatrix.SetRow(3, new[] { 0f, 0f, 0f, 1f }); Matrix zRotationMatrix = new DenseMatrix(4, 4); zRotationMatrix.SetRow(0, new[] { cosZ, -sinZ, 0f, 0f }); zRotationMatrix.SetRow(1, new[] { sinZ, cosZ, 0f, 0f }); zRotationMatrix.SetRow(2, new[] { 0f, 0f, 1f, 0f }); zRotationMatrix.SetRow(3, new[] { 0f, 0f, 0f, 1f }); return(zRotationMatrix * yRotationMatrix * xRotationMatrix); }
public static float[] NextPoint(float x, float y, float a, float dist) { var newx = x + (Trig.Sin(Trig.DegreeToRadian(a)) * dist); var newy = y + (Trig.Cos(Trig.DegreeToRadian(a)) * dist); return(new[] { Convert.ToSingle(newx), Convert.ToSingle(newy) }); }
public void Priority_OfACircleThrough0N45EAnd45N0EAnd0N45W_ShouldBeCorrect() { // Fixture setup var arcA = new Arc { Site = Utilities.SiteAt(90, 45) }; var arcB = new Arc { Site = Utilities.SiteAt(45, 0) }; var arcC = new Arc { Site = Utilities.SiteAt(90, -45) }; var circle = new CircleEvent(arcA, arcB, arcC); // Exercise system var result = circle.Priority; // Verify outcome var expectedResult = -Trig.Cosine(Trig.DegreeToRadian(135)) - 1; Debug.WriteLine(expectedResult); var failureString = String.Format("Priority was {0}", result); Assert.True(Number.AlmostEqual(result, expectedResult, Tolerance), failureString); // Teardown }
public Camera() { Eye = DenseVector.OfArray(new[] { 1000000.0, 1000000.0, 1000000.0 }); Target = DenseVector.OfArray(new[] { 0.0, 0.0, 0.0 }); Up = DenseVector.OfArray(new[] { 0.0, 1.0, 0.0 }); Fov = Trig.DegreeToRadian(40.0); SetViewMatrix(); SetProjectionMatrix(); }
public XyzPoint ToXyzPoint() { //var dec = DmsAngle.FromDecimal(Declination); //var b = Math.Sign(Declination) * // (Math.Abs(dec.Degrees) + dec.Minutes / 60.0 + dec.Seconds / 3600.0); var ra = Trig.DegreeToRadian(RightAscension); var dec = Trig.DegreeToRadian(Declination); return(new XyzPoint { X = Distance * Math.Cos(dec) * Math.Cos(ra), Y = Distance * Math.Cos(dec) * Math.Sin(ra), Z = Distance * Math.Sin(dec) }); }
public void Rotate(Vector3D rotationAmount) { var rotationAroundX = new Matrix3D(); rotationAroundX.Rotate(new Quaternion(Right, Trig.DegreeToRadian(rotationAmount.Y))); var rotationAroundY = new Matrix3D(); rotationAroundY.Rotate(new Quaternion(Up, Trig.DegreeToRadian(rotationAmount.X))); var rotationMatrix = Matrix3D.Multiply(rotationAroundX, rotationAroundY); Direction = Vector3D.Multiply(Direction, rotationMatrix); Up = Vector3D.Multiply(Up, rotationMatrix); UpdateSettings(); }
public void CanConvertDegreeToRadian() { AssertHelpers.AlmostEqual(Math.PI / 2, Trig.DegreeToRadian(90), 15); }
/// <summary> /// Converts an angle to a 2d vector that points in the direction of the angle. /// </summary> /// <param name="angle">The angle in degrees</param> /// <returns>A 2d vector</returns> public static Vector <float> AngleToVector(float angle) { return(new DenseVector(new[] { (float)Math.Cos(Trig.DegreeToRadian(angle)), (float)Math.Sin(Trig.DegreeToRadian(angle)) })); }
public static double DegreeToRadian(double degree) { return(Trig.DegreeToRadian(degree)); }
/// <summary> /// Spawns cubes upon an arc of an ellipse. /// </summary> /// <param name="n"> The number of cubes. </param> /// <param name="center"> The center of the ellipse. </param> /// <param name="sectorChordLength"> The length of the arc's chord. </param> /// <param name="semiMinorAxisLength"> Half the length of the minor axis. </param> /// <param name="sectorAngleDeg"> The angular length of the arc in degrees. </param> /// <param name="cubePrefab"> The template for the cubes. </param> /// <param name="parent"> The parent of the cubes structure. </param> /// <returns> Returns the GameObject containing the cubes, whose parent is 'parent'. </returns> /// <remarks> This function is definitely very time-expensive. Use sparingly. </remarks> private static GameObject SpawnEllipseCubes(int n, Vector3 center, float sectorChordLength, float semiMinorAxisLength, float sectorAngleDeg, GameObject cubePrefab, Transform parent = null) { // TODO: Find constraints for every parameter and variable (minimum and maximum values) // Problem: for some combination of input parameters, the FindRoots.OfFunction method fails with an exception: // "ArithmeticException: Function does not accept floating point Not-a-Number values." // Sample parameters: (16,, 12.0f, 6.0f, 90°,,) #region Maths /* * C: center of the ellipse * R: sectorChordLength, the length of the chord * a: half the length of the major axis of the ellipse * b: semiMinorAxisLength, half the length of the minor axis of the ellipse * α: sectorAngleDeg, the sector extension in degrees, from (90° - α/2) to (90° + α/2) counterclock-wise * n: number of cubes * * * § 1) ELLIPSE'S EQUATIONS * * ξ(ϑ): ellipse's parametric equations [-180° ≤ ϑ ≤ 180°] * where ϑ is the angle of (ξˣ(ϑ), ξʸ(ϑ)) with the major axis of the ellipse itself * ___________________________ * ξˣ(ϑ) = a b cos(ϑ) √(a² sin²(ϑ) + b² cos²(ϑ))⁻¹ * ___________________________ * ξʸ(ϑ) = a b sin(ϑ) √(a² sin²(ϑ) + b² cos²(ϑ))⁻¹ * * A = ξ(90° + α/2) * B = ξ(90° - α/2) * * __ _______________________________ * R = AB = 2 a b sin(α/2) √(a² cos²(α/2) + b² sin²(α/2))⁻¹ * _________________________________________ _______________________ * a = √(b² R² tan²(α/2)) / (4 b² tan²(α/2) - R²) = (b R tan(α/2)) √(4 b² tan²(α/2) - R²)⁻¹ * * * § 2) CUBES PLACEMENT * A _____________________ * L = ∫(√D[ξˣ(ϑ)]² + D[ξʸ(ϑ)]²)dϑ: length of arc AB * B * l = L/n: distance between each cube's center on the arc * * θᵢ: angle of the iᵗʰ arc segment; arc length to the iᵗʰ arc segment = i l * θᵢ = FindRoot[∫(D[ξˣ(ϑ)]² + D[ξʸ(ϑ)]²)dϑ = i l] 😭 * * Pᵢ = ξ(θᵢ): position of the iᵗʰ cube * * * § 3) CUBES' SIDE LENGTH * Let Pᵢ and Pⱼ be the positions of two consecutive cubes (j = i + 1) with angles θᵢ and θⱼ. * Let Pₖ be a third point placed at the same arc-distance from both Pᵢ and Pⱼ; the angle of Pₖ is θₖ. * * rₖ: line from C to Pₖ * rᵢ: line from C to Pᵢ * rⱼ: line from C to Pⱼ * * M: parametric point on rₖ * dᵢ: segment MPᵢ * dⱼ: segment MPⱼ * * * M = (mˣ, mʸ) = (mˣ, mˣ tan(θₖ)) * ____________________________________ * dᵢ = √(x(Pᵢ) - mˣ)² + (y(Pᵢ) - mˣ tan(θₖ))² * ____________________________________ * dⱼ = √(x(Pⱼ) - mˣ)² + (y(Pⱼ) - mˣ tan(θₖ))² * * ASSERTION * dᵢ = dⱼ = d: dᵢ and dⱼ are the semi-diagonals of the two squares * * (x(Pᵢ) - mˣ)² + (y(Pᵢ) - mˣ tan(θₖ))² = (x(Pⱼ) - mˣ)² + (y(Pⱼ) - mˣ tan(θₖ))² * x(Pᵢ)² + (mˣ)² - 2 x(Pᵢ) mˣ + y(Pᵢ)² + (mˣ tan(θₖ))² - 2 y(Pᵢ) mˣ tan(θₖ) = x(Pⱼ)² + (mˣ)² - 2 x(Pⱼ) mˣ + y(Pⱼ)² + (mˣ tan(θₖ))² - 2 y(Pⱼ) mˣ tan(θₖ) * x(Pᵢ)² - 2 x(Pᵢ) mˣ + y(Pᵢ)² - 2 y(Pᵢ) mˣ tan(θₖ) = x(Pⱼ)² - 2 x(Pⱼ) mˣ + y(Pⱼ)² - 2 y(Pⱼ) mˣ tan(θₖ) * 2 x(Pⱼ) mˣ + 2 y(Pⱼ) mˣ tan(θₖ) - 2 x(Pᵢ) mˣ - 2 y(Pᵢ) mˣ tan(θₖ) = x(Pⱼ)² + y(Pⱼ)² - x(Pᵢ)² - y(Pᵢ)² * 2 mˣ (x(Pⱼ) + y(Pⱼ) tan(θₖ) - x(Pᵢ) - y(Pᵢ) tan(θₖ)) = x(Pⱼ)² + y(Pⱼ)² - x(Pᵢ)² - y(Pᵢ)² * * x(Pⱼ)² + y(Pⱼ)² - x(Pᵢ)² - y(Pᵢ)² * mˣ = —————————————————————————————————————————————————— * 2 (x(Pⱼ) + y(Pⱼ) tan(θₖ) - x(Pᵢ) - y(Pᵢ) tan(θₖ)) * * cube's side length = 2 (d/√2) * */ #endregion Maths double R = sectorChordLength; double b = semiMinorAxisLength; #region § 1) ELLIPSE'S EQUATION double alphaRad = Trig.DegreeToRadian(sectorAngleDeg); double bTanHalfAlpha = b * Trig.Tan(alphaRad / 2.0); double a = (R * bTanHalfAlpha) / Math.Sqrt(4 * bTanHalfAlpha * bTanHalfAlpha - R * R); Func <double, double> EllipseX = t => { double sin = Trig.Sin(t); double cos = Trig.Cos(t); double aSin = a * sin; double bCos = b * cos; return((a * bCos) / Math.Sqrt(aSin * aSin + bCos * bCos)); }; Func <double, double> EllipseY = t => { double sin = Trig.Sin(t); double cos = Trig.Cos(t); double aSin = a * sin; double bCos = b * cos; return((b * aSin) / Math.Sqrt(aSin * aSin + bCos * bCos)); }; #endregion § 1) ELLIPSE'S EQUATION #region § 2) CUBES PLACEMENT Func <double, double> DEllipseX = Differentiate.FirstDerivativeFunc(EllipseX); Func <double, double> DEllipseY = Differentiate.FirstDerivativeFunc(EllipseY); Func <double, double> SqrtOfSumOfSquaredDerivatives = t => { double x = DEllipseX(t); double y = DEllipseY(t); return(Math.Sqrt(x * x + y * y)); }; Func <double, double, double> AngleToArcLength = (fromRad, toRad) => Integrate.OnClosedInterval(SqrtOfSumOfSquaredDerivatives, fromRad, toRad); Func <double, double> ArcLengthToAngle = arcLength => FindRoots.OfFunction(toRad => AngleToArcLength((Math.PI - alphaRad) / 2, toRad) - arcLength, 0, Math.PI); double L = AngleToArcLength((Math.PI - alphaRad) / 2, (Math.PI + alphaRad) / 2); double l = L / (n - 1); Func <int, object[]> CalculateCubePositionAndAngle = i => { double angle = ArcLengthToAngle(i * l); Vector2 position = new Vector2((float)EllipseX(angle), (float)EllipseY(angle)); return(new object[] { position, angle }); }; #endregion § 2) CUBES PLACEMENT #region § 3) CUBES' SIDE LENGTH Vector2[] positions = new Vector2[n]; double[] angles = new double[n]; double[] middleAngles = new double[n - 1]; for (int i = 0; i < n; ++i) { object[] res = CalculateCubePositionAndAngle(i); positions[i] = (Vector2)res[0]; angles[i] = (double)res[1]; if (i > 0) { middleAngles[i - 1] = ArcLengthToAngle((2 * i - 1) * l / 2.0); } } double[] sideLengths = new double[n - 1]; Func <int, double> SideLength = j => { double xj = positions[j].x; double yj = positions[j].y; double xi = positions[j - 1].x; double yi = positions[j - 1].y; double tanK = Trig.Tan(middleAngles[j - 1]); double mx = (xj * xj + yj * yj - (xi * xi + yi * yi)) / (2.0 * (xj + yj * tanK - (xi + yi * tanK))); return(Math.Sqrt((xi - mx) * (xi - mx) + (yi - mx * tanK) * (yi - mx * tanK)) * (2.0 / Math.Sqrt(2.0))); }; for (int i = 1; i < n; ++i) { sideLengths[i - 1] = SideLength(i); } float squareSide = (float)sideLengths.Min(); #endregion § 3) CUBES' SIDE LENGTH // Save parent's current local rotation and scale; it will be re-set later Quaternion parentRotation = parent?.localRotation ?? Quaternion.identity; Vector3 parentScale = parent?.localScale ?? Vector3.one; if (parent != null) { parent.localRotation = Quaternion.identity; parent.localScale = Vector3.one; } GameObject cubesContainer = parent?.gameObject ?? new GameObject(); cubesContainer.name = $"Ellipse_{n}Cubes"; cubesContainer.transform.localPosition = center; // Create the cubes for (int i = 0; i < n; ++i) { GameObject cube = Instantiate(cubePrefab); cube.name = $"Cube{i}"; cube.SetActive(true); // Awake it now, to let it store the prefab's original scale cube.transform.localScale = new Vector3(squareSide, squareSide, squareSide); cube.transform.position = cubesContainer.transform.position + new Vector3(positions[i].x, 0.0f, positions[i].y); cube.transform.localRotation = Quaternion.Euler(0.0f, (float)(90.0 - Trig.RadianToDegree(angles[i])), 0.0f); cube.transform.parent = cubesContainer.transform; } cubesContainer.transform.localRotation = Quaternion.identity; // Re-set parent's original local rotation if (parent != null) { parent.localRotation = parentRotation; parent.localScale = parentScale; } return(cubesContainer); }
/// <summary> /// Spaws cubes upon a circumference. /// </summary> /// <param name="n"> Number of cubes. </param> /// <param name="center"> Center of the circumference in local coordinates. </param> /// <param name="radius"> Radius of the circumference. </param> /// <param name="cubePrefab"> Cubes template. </param> /// <param name="parent"> Parent of the cubes structure. </param> /// <returns> Returns the GameObject containing the cubes, whose parent is 'parent'. </returns> private static GameObject SpawnCircCubes(int n, Vector3 center, float radius, GameObject cubePrefab, Transform parent = null) { #region Maths /* * C: center; R: radius; δ = 360°/n: deltaDegree * P, Q: first and second points on the circumference * t: bisectrix of angle PCQ * M: parametric point on t * p: line through M, perpendicular to PC * J: intersection of p and segment PC * d: distance from point M to point J * l: distance from point P to point J * * CONDITIONS: * 1) 0° ≤ δ ≤ 90° * There should be at least 4 cubes * 2) d == l * MJ must be half of the square's side * 3) length of segment MC <= R * M must be inside the circumference * * * C = [0, 0]; P = [0, R]; Q = [-R sin(δ), R cos(δ)] * random point on bisectrix: B = [-R sin(δ/2), R cos(δ/2)] * t: y = -(R cos(δ/2) / R sin(δ/2)) x = -x cotg(δ/2) * M = k * B = [-k R sin(δ/2), k R cos(δ/2)] * p: y = k R cos(δ/2) * J = [0, k R cos(δ/2)] * * 1) * 0° ≤ δ/2 ≤ 45° => 1 ≥ cos(δ/2) ≥ √2/2 * 0 ≤ sin(δ/2) ≤ √2/2 * * 2) ____________________________________________________ * { d = √(0 + k R sin(δ/2))² + (k R cos(δ/2) - k R cos(δ/2))² = | k R sin(δ/2) | * { ______________________________ * { l = √(0 - 0)² + (k R cos(δ/2) - R)² = | k R cos(δ/2) - R| * * | k R sin(δ/2) | = | k R cos(δ/2) - R | * k R cos(δ/2) - R = ± k R sin(δ/2) * k (cos(δ/2) ∓ sin(δ/2)) = 1 * k = 1 / (cos(δ/2) ∓ sin(δ/2)) * * 1+2) * k > 0 always ✓ * * 3) * ‖M‖ = ‖k * B‖ < R * _______________________________ * √k²R² sin²(δ/2) + k²R² cos²(δ/2) < R * k R < R * k < 1 * * 2+3) * k < 1 <=> cos(δ/2) ∓ sin(δ/2) > 1 * hence, must be k = 1 / (cos(δ/2) + sin(δ/2)) * * * CONCLUSION: * square side = 2 * length of MJ * M = [-(cos(δ/2) + sin(δ/2))⁻¹ R sin(δ/2), (cos(δ/2) + sin(δ/2))⁻¹ R cos(δ/2)] * J = [0, (cos(δ/2) + sin(δ/2))⁻¹ R cos(δ/2)] * _____________________________________________ * length of MJ = √(0 + (cos(δ/2) + sin(δ/2))⁻¹ R sin(δ/2))² + 0 = (cos(δ/2) + sin(δ/2))⁻¹ R sin(δ/2) * square side = 2 R sin(δ/2) (cos(δ/2) + sin(δ/2))⁻¹ * */ #endregion Maths float deltaDegrees = 360.0f / n; double deltaRadians = Trig.DegreeToRadian(deltaDegrees); float squareSide = (float)(2.0 * radius * Math.Sin(deltaRadians / 2) * (1 / (Math.Cos(deltaRadians / 2) + Math.Sin(deltaRadians / 2)))); // Save parent's current local rotation; it will be re-set later Quaternion parentRotation = parent?.localRotation ?? Quaternion.identity; if (parent != null) { parent.localRotation = Quaternion.identity; } GameObject cubesContainer = parent?.gameObject ?? new GameObject(); cubesContainer.name = $"Circumference_{n}Cubes"; cubesContainer.transform.localPosition = center; // Create the cubes for (int i = 0; i < n; ++i) { cubesContainer.transform.localEulerAngles = new Vector3(0.0f, -deltaDegrees * i, 0.0f); GameObject cube = Instantiate(cubePrefab); cube.name = $"Cube{i}"; cube.SetActive(true); // Awake it now, to let it store the prefab's original scale cube.transform.localScale = new Vector3(squareSide, squareSide, squareSide); cube.transform.position = cubesContainer.transform.position + Vector3.forward * radius; cube.transform.parent = cubesContainer.transform; } cubesContainer.transform.localRotation = Quaternion.identity; // Re-set parent's original local rotation if (parent != null) { parent.localRotation = parentRotation; } return(cubesContainer); }
public static Sweepline SweeplineAt(double colatitude) { return(new Sweepline { Colatitude = Trig.DegreeToRadian(colatitude) }); }
public static Vector3 VectorAt(double colatitude, double azimuth) { return(new SphericalCoords(Trig.DegreeToRadian(colatitude), Trig.DegreeToRadian(azimuth)).CartesianCoordinates()); }