WIP on redoing rotate transform as shears instead to avoid holes in the output (partially addresses #485, but still more to test and fix)

This commit is contained in:
UnknownShadow200 2022-10-04 08:52:44 +11:00
parent d5ae8f0c25
commit e586b9d0e5

View File

@ -26,17 +26,31 @@ namespace MCGalaxy.Drawing.Transforms
{
public override string Name { get { return "Rotate"; } }
public bool CentreOrigin;
double cosX, cosY, cosZ, sinX, sinY, sinZ;
double alphaX, betaX, alphaY, betaY, alphaZ, betaZ;
Vec3S32 P;
public void SetAngles(double xDeg, double yDeg, double zDeg) {
cosX = Math.Cos(xDeg * Math.PI / 180.0);
cosY = Math.Cos(yDeg * Math.PI / 180.0);
cosZ = Math.Cos(zDeg * Math.PI / 180.0);
// https://silmon.github.io/arbitrary-image-rotation-using-shearing.html
// http://delta.cs.cinvestav.mx/~mcintosh/newweb/camex/node37.html
// https://www.ocf.berkeley.edu/~fricke/projects/israel/paeth/rotation_by_shearing.html
sinX = Math.Sin(xDeg * Math.PI / 180.0);
sinY = Math.Sin(yDeg * Math.PI / 180.0);
sinZ = Math.Sin(zDeg * Math.PI / 180.0);
public void SetAngles(double xDeg, double yDeg, double zDeg) {
CalcShear2D(xDeg, out alphaX, out betaX);
CalcShear2D(yDeg, out alphaY, out betaY);
CalcShear2D(zDeg, out alphaZ, out betaZ);
}
void CalcShear2D(double angle, out double alpha, out double beta) {
angle *= -Math.PI / 180.0; // degrees -> radians, and - so same direction as old RotateTransform
alpha = -Math.Tan(angle / 2);
beta = Math.Sin(angle);
}
void Shear2D(ref int x, ref int y, double alpha, double beta) {
int x_ = (int)(x + alpha * (y + 0.5)); // shear #1
int y_ = (int)(y + beta * (x_ + 0.5)); // shear #2
int X_ = (int)(x_ + alpha * (y_ + 0.5)); // shear #3
x = X_; y = y_;
}
public override void Perform(Vec3S32[] marks, DrawOp op, Brush brush, DrawOpOutput output) {
@ -46,27 +60,15 @@ namespace MCGalaxy.Drawing.Transforms
}
void OutputBlock(DrawOpBlock b, DrawOpOutput output) {
double dx = b.X - P.X, dy = b.Y - P.Y, dz = b.Z - P.Z;
double rotX = 0, rotY = 0, rotZ = 0;
int dx = b.X - P.X, dy = b.Y - P.Y, dz = b.Z - P.Z;
// Rotate X
rotY = cosX * dy - sinX * dz;
rotZ = sinX * dy + cosX * dz;
dy = rotY; dz = rotZ;
Shear2D(ref dy, ref dz, alphaX, betaX);
Shear2D(ref dx, ref dz, alphaY, betaY);
Shear2D(ref dx, ref dy, alphaZ, betaZ);
// Rotate Y
rotX = cosY * dx + sinY * dz;
rotZ = -sinY * dx + cosY * dz;
dx = rotX; dz = rotZ;
// Rotate Z
rotX = cosZ * dx - sinZ * dy;
rotY = sinZ * dx + cosZ * dy;
dx = rotX; dy = rotY;
b.X = (ushort)(dx + P.X + ((dx % 1) >= 0.5 ? 1 : 0));
b.Y = (ushort)(dy + P.Y + ((dy % 1) >= 0.5 ? 1 : 0));
b.Z = (ushort)(dz + P.Z + ((dz % 1) >= 0.5 ? 1 : 0));
b.X = (ushort)(P.X + dx);
b.Y = (ushort)(P.Y + dy);
b.Z = (ushort)(P.Z + dz);
output(b);
}
}