ex-rep-04/PinwheelTiling/PinwheelTilingPath.cs
2024-10-09 17:37:52 +02:00

164 lines
6.4 KiB
C#

using System.Collections.Immutable;
using System.Reflection.Metadata;
using Avalonia.Controls.Selection;
using LeoTurtle;
namespace PinwheelTiling;
public static class PinwheelTilingPath
{
private const double Alpha = 26.57D;
private const double Beta = 90D - Alpha;
private const double Gamma = 90D;
private static Point _startPoint = new Point(0, 0.2);
private static Point _endPoint = new Point(0, 0);
/// <summary>
/// Executes the logic for adding turtle path steps.
/// Called automatically when application starts.
/// </summary>
/// <param name="turtle">The <see cref="SmartTurtle"/> instance to use</param>
public static void Walk(SmartTurtle turtle)
{
var initialTriangle = new Triangle(new Point(2.5D, 10.0D), new Point(82.5D, 50.0D), new Point(82.5D, 10.0D));
const double sideA = 40.0D;
const double sideB = 80.0D;
const int depth = 1;
_endPoint = new Point(_startPoint.X + sideB, _startPoint.Y + sideA);
Triangle triangle = MakeTriangle(_startPoint, _endPoint);
MakeRecursiveTriangle(turtle, triangle, depth);
}
private static void MakeRecursiveTriangle(SmartTurtle turtle, Triangle triangle, int depth = 0)
{
if (depth == 0)
{
return;
}
depth--;
Triangle[] subdivision = GetSubdivision(triangle);
DrawSubdivision(turtle, subdivision);
for (int i = 0; i < subdivision.Length; i++)
{
MakeRecursiveTriangle(turtle, subdivision[i], depth);
}
}
private static Triangle MakeTriangle(Point startingPoint,
Point endingPoint)
{
Point pointA = startingPoint;
Point pointB = endingPoint;
Point pointC = new Point(endingPoint.X, startingPoint.Y);
return new Triangle(pointA, pointB, pointC);
}
private static Triangle[] GetSubdivision(Triangle triangle)
{
double sideA = DistanceBetweenPoints(triangle.B, triangle.C);
double sideB = DistanceBetweenPoints(triangle.A, triangle.C);
double sideC = CalculateHyptonuse(sideA, sideB);
Point startingPoint = new Point(triangle.A.X, triangle.A.Y);
Point endingPoint = new Point(triangle.B.X, triangle.B.Y);
//calculate parent sides
double height = CalculateHeight(sideA, sideB, sideC);
double sideE = height / 2;
//double sideF = CalculateHyptonuse(sideE, height);
//calculate additional sides that are part of the parent triangle
double sideB1 = sideB / 2;
double sideC1 = Math.Sqrt(Math.Pow(sideA, 2) - Math.Pow(height, 2));
//double sideC2;
double sideC3 = Math.Sqrt(Math.Pow(sideB1, 2) - Math.Pow(sideE, 2));
//calculate additional sides that are |not part/not important at all| for the parent triangle
double heightOfTriangle0 = CalculateHeight(sideC1, height, sideA);
double heightOfTriangle1 = CalculateHeight(sideE, height, sideB1);
double heightOfTriangle2 = CalculateHeight(sideE, sideC3, sideB1);
double sideB1SegmentOfTriangle1 = Math.Sqrt(Math.Pow(sideE, 2) - Math.Pow(heightOfTriangle1, 2));
double sideB1SegmentOfTriangle2 = Math.Sqrt(Math.Pow(sideE, 2) - Math.Pow(heightOfTriangle2, 2));
double heightOfAllExceptTriangle0 = CalculateHeight(height, sideC - sideC1, sideB);
double sideB1SegmentOfAllTrianglesExcept0
= Math.Sqrt(Math.Pow(sideC - sideC1, 2) - Math.Pow(heightOfAllExceptTriangle0, 2));
//create Points
Point pointA = startingPoint;
Point pointB = endingPoint;
Point pointC = new Point(endingPoint.X, startingPoint.Y);
Point pointD = new Point(startingPoint.X + sideB1SegmentOfAllTrianglesExcept0, startingPoint.Y + heightOfAllExceptTriangle0);
Point pointE = new Point(startingPoint.X + sideB1 - sideB1SegmentOfTriangle2, startingPoint.Y + heightOfTriangle2);
Point pointF = new Point(startingPoint.X + sideB1, startingPoint.Y);
Point pointH = new Point(startingPoint.X + sideB - sideB1SegmentOfTriangle1, startingPoint.Y + heightOfTriangle1);
Triangle triangle0 = new Triangle(pointC, pointB, pointD);
Triangle triangle1 = new Triangle(pointF, pointC, pointH);
Triangle triangle2 = new Triangle(pointA, pointF, pointE);
Triangle triangle3 = new Triangle(pointF, pointD, pointH);
Triangle triangle4 = new Triangle(pointD, pointF, pointE);
Triangle[] subdivisionTriangles = { triangle0, triangle1, triangle2, triangle3, triangle4 };
return subdivisionTriangles;
double CalculateHeight(double a, double b, double c) => a * b / c;
}
private static void DrawSubdivision(SmartTurtle turtle, Triangle[] subdivision)
{
foreach (var triangle in subdivision)
{
DrawSimpleTriangle(turtle, triangle);
}
}
private static void DrawSimpleTriangle(SmartTurtle turtle, Triangle triangle)
{
turtle.Teleport(triangle.A.X, triangle.A.Y);
double sideAB = DistanceBetweenPoints(triangle.A, triangle.B);
double sideBC = DistanceBetweenPoints(triangle.B, triangle.C);
double sideCA = DistanceBetweenPoints(triangle.C, triangle.A);
turtle.LookAt(triangle.B.X, triangle.B.Y);
turtle.MoveForward(sideAB);
turtle.LookAt(triangle.C.X, triangle.C.Y);
turtle.MoveForward(sideBC);
turtle.LookAt(triangle.A.X, triangle.A.Y);
turtle.MoveForward(sideCA);
}
private static double CalculateHyptonuse(double a, double b)
{
return Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2));
}
/// <summary>
/// Converts an angel from degrees to radians.
/// </summary>
/// <param name="angleDegrees">Degrees to convert</param>
/// <returns>Radians value</returns>
private static double ConvertToRadians(double angleDegrees)
{
return angleDegrees * Math.PI / 180D;
}
/// <summary>
/// Calculates the distance between two points.
/// </summary>
/// <param name="a">First point</param>
/// <param name="b">Second point</param>
/// <returns>Distance between the two points</returns>
private static double DistanceBetweenPoints(Point a, Point b)
{
return Math.Sqrt(Math.Pow(b.X - a.X, 2D) + Math.Pow(b.Y - a.Y, 2D));
}
}