private static Isometry SetupIsometry(Cell clickedCell, Vector3D clickedPoint, Puzzle puzzle) { int p = puzzle.Config.P; Geometry g = puzzle.Config.Geometry; Isometry cellIsometry = clickedCell.Isometry.Clone(); // Take out reflections. // ZZZ - Figuring out how to deal with these reflected isometries was a bit painful to figure out. // I wish I had just taken more care to not have any cell isometries with reflections. // Maybe I can rework that to be different at some point. if (cellIsometry.Reflection != null) { cellIsometry = Isometry.ReflectX() * cellIsometry; } // Round to nearest vertex. Vector3D centered = cellIsometry.Apply(clickedPoint); double angle = Euclidean2D.AngleToCounterClock(centered, new Vector3D(1, 0)); double angleFromZeroToP = p * angle / (2 * Math.PI); angleFromZeroToP = Math.Round(angleFromZeroToP, 0); if (p == (int)angleFromZeroToP) { angleFromZeroToP = 0; } angle = 2 * Math.PI * angleFromZeroToP / p; // This will take vertex to canonical position. Mobius rotation = new Mobius(); rotation.Isometry(g, angle, new Complex()); Isometry rotIsometry = new Isometry(rotation, null); return(rotIsometry * cellIsometry); }
/// <summary> /// Transforms us into a new macro based on a different click location. /// </summary> public Macro Transform(Cell clickedCell, Vector3D clickedPoint, Puzzle puzzle, bool mouseMotionReflected) { Macro m = this.CloneAllButTwists(); m.SetupMobius(clickedCell, clickedPoint, puzzle, mouseMotionReflected); // Did we have an odd number of view reflections? bool viewReflected = this.ViewReflected ^ m.ViewReflected; Isometry iso1 = new Isometry(m.Mobius, null); Isometry iso2 = new Isometry(this.Mobius, null); if (viewReflected) { iso1 = Isometry.ReflectX() * iso1; } Isometry combined = iso1.Inverse() * iso2; foreach (SingleTwist t in this.m_twists) { // Find the transformed twist data. // NOTE: We choose the one which will be closest to the origin after transformation, // which hopefully won't lead to performance problems. // I initially just used the first TwistDataForStateCalcs list item, // but that led to issues because sometimes it would get transformed // to very near the disk boundary. We'd have run out of cells to // find the correct closest, and the transformed macros got all messed up. TwistData tdOriginal = t.IdentifiedTwistData.TwistDataForStateCalcs .OrderBy(td => combined.Apply(td.Center).MagSquared()) .First(); Vector3D newCenter = combined.Apply(tdOriginal.Center); TwistData tdNew = puzzle.ClosestTwistingCircles(newCenter); SingleTwist tClone = t.Clone(); tClone.IdentifiedTwistData = tdNew.IdentifiedTwistData; // If the reverse state of our transformed twist // has changed, we may need to reverse the new twist. bool reverse = tdOriginal.Reverse ^ tdNew.Reverse; if (reverse ^ viewReflected) // NOTE: Very similar to code in Renderer. { tClone.ReverseTwist(); } m.m_twists.Add(tClone); } return(m); }