internal void CloseSMatrixSet() { if (Pole.Length == 4) { PGeom.CloseMatrixSet(SMatrices); } }
private void CreateTwistMaps() { PermByMatr perm = new PermByMatr(Axes.Length, Faces.Length); foreach (PBaseAxis Ax in BaseAxes) { foreach (PBaseTwist tw in Ax.Twists) { double[,] matr = PGeom.ApplyTwist(tw.Dir, PGeom.MatrixIdentity(Dim)); int[][] R = ConvertStickersFromLayers(Ax, matr, perm); int[][] R1 = new int[Ax.NLayers][]; for (int i = 0; i < Ax.NLayers; i++) { if (R[i] != null) { R1[i] = new int[R[i].Length]; for (int j = 0; j < R[i].Length; j++) { int h = Array.BinarySearch <int>(Ax.Layers[i], R[i][j]); if (h < 0) { throw new Exception("Can't find sticker image in twist"); } R[i][j] = h; R1[i][h] = j; } } } tw.Map = R; tw.InvMap = R1; } } }
internal double[,] GetBestMatrix(int f0, double[] p0, int f1, double[] p1) { // move from (f0,p0) to (f1,p1); point p is on the cell surface. PFace F0 = Faces[f0], F1 = Faces[f1]; if (F0.Base.Id != F1.Base.Id) { return(null); } double[] q0 = PGeom.ApplyInvMatrix(F0.Matrix, p0); double[] q1 = PGeom.ApplyInvMatrix(F1.Matrix, p1); double dbest = double.MaxValue; double[,] mr = null; foreach (double[,] m in F0.Base.SMatrices) { double[] qq = PGeom.ApplyMatrix(m, q0); double v = PGeom.Dist2(qq, q1); if (v < dbest) { dbest = v; mr = m; } } return(PGeom.MatrixMulInv2(F0.Matrix, PGeom.MatrixMul(mr, F1.Matrix))); }
internal PFace(PBaseFace bas) { Base = bas; Pole = bas.Pole; int dim = Pole.Length; Matrix = PGeom.MatrixIdentity(dim); RefAxis = 0; }
internal int FindTwist(double[] p, double[,] matr, out bool qrev) { double[] q = PGeom.ApplyMatrixToTwist(matr, p); qrev = false; for (int i = 0; i < Twists.Length; i++) { if (PGeom.TwistsEqual(q, Twists[i], out qrev)) { return(i); } } throw new Exception("Can't fing twist"); }
internal PAxis(PAxis src, double [] tw) { Base = src.Base; Dir = PGeom.ApplyTwist(tw, src.Dir); Matrix = PGeom.ApplyTwist(tw, src.Matrix); int ntw = src.Twists.Length; Twists = new double[ntw][]; for (int i = 0; i < ntw; i++) { Twists[i] = PGeom.ApplyTwist(tw, src.Twists[i]); } }
internal void AddSMatrix(double[,] mf, double[,] p) { // Pole*mf=Pole*p => Pole*(mf*p')=Pole double[,] mr = PGeom.MatrixMulInv(mf, p); foreach (double[,] m in SMatrices) { if (PGeom.MatrixEqual(m, mr)) { return; } } SMatrices.Add(mr); }
internal PAxis(PBaseAxis bas) { Base = bas; Dir = bas.Dir; int dim = Dir.Length; Matrix = PGeom.MatrixIdentity(dim); int ntw = bas.Twists.Length; Twists = new double[ntw][]; for (int i = 0; i < ntw; i++) { Twists[i] = bas.Twists[i].Dir; } }
private void ExpandFaces() { PFace[] CFaces = new PFace[MaxNVert]; int NRefl = Group.Length; int p, q = BaseFaces.Length; for (int i = 0; i < q; i++) { BaseFaces[i].Id = i; CFaces[i] = new PFace(BaseFaces[i]); } for (p = 0; p < q; p++) { foreach (double [] G in Group) { double[] v = PGeom.ApplyTwist(G, CFaces[p].Pole); int j; for (j = 0; j < q; j++) { if (PGeom.VertEqual(v, CFaces[j].Pole)) { double[,] mf = PGeom.ApplyTwist(G, CFaces[p].Matrix); CFaces[p].Base.AddSMatrix(mf, CFaces[j].Matrix); break; } } if (j == q) { if (q == MaxNVert) { throw new Exception("Too many vertices"); } CFaces[q] = new PFace(CFaces[p], G); q++; } } } Faces = new PFace[q]; for (int i = 0; i < q; i++) { Faces[i] = CFaces[i]; Faces[i].Id = i; } foreach (PBaseFace BF in BaseFaces) { BF.CloseSMatrixSet(); } }
private int FindFace(double[] p, double[,] matr) { p = PGeom.ApplyMatrix(matr, p); int r0 = 0; double d0 = double.MaxValue; foreach (PFace F in Faces) { double v = PGeom.Dist2(p, F.Pole); if (v < d0) { d0 = v; r0 = F.Id; } } return(r0); }
private void ExpandAxes() { int q = BaseAxes.Length; PAxis[] CAxes = new PAxis[MaxNAxes]; for (int i = 0; i < q; i++) { PBaseAxis ax = BaseAxes[i]; ax.Id = i; ax.ExpandPrimaryTwists(); CAxes[i] = new PAxis(ax); // matrix=id } for (int p = 0; p < q; p++) { double[] R = CAxes[p].Dir; foreach (double [] G in Group) { double[] v = PGeom.ApplyTwist(G, R); int j; bool qr; for (j = 0; j < q; j++) { if (PGeom.AxisEqual(v, CAxes[j].Dir, out qr)) { break; } } if (j == q) { if (q == MaxNAxes) { throw new Exception("Too many axes"); } CAxes[q] = new PAxis(CAxes[p], G); q++; } } } Axes = new PAxis[q]; for (int i = 0; i < q; i++) { Axes[i] = CAxes[i]; Axes[i].Id = i; } }
internal void ExpandPrimaryTwists() { const int MaxNTwists = 256; NPrimaryTwists = Twists.Length; PBaseTwist[] twst = new PBaseTwist[MaxNTwists]; int q = 0; foreach (PBaseTwist tw in Twists) { twst[q++] = tw; } for (int p = 0; p < q; p++) { double[] v = twst[p].Dir; for (int i = 0; i < q; i++) { double[] w = PGeom.ApplyTwist(twst[i].Dir, v); int k; bool qr; for (k = 0; k < q; k++) { if (PGeom.TwistsEqual(w, twst[k].Dir, out qr)) { break; } } if (k == q) { if (q == MaxNTwists) { throw new Exception("Too many planes"); } twst[q] = new PBaseTwist(w); q++; } } } Twists = new PBaseTwist[q]; for (int i = 0; i < q; i++) { Twists[i] = twst[i]; } }
internal double GetRad() { double R = 0; foreach (PBaseFace F in BaseFaces) { foreach (PMesh M in F.StickerMesh) { if (M.MinBDim == 0) { double r = PGeom.VLength(M.Ctr); if (r > R) { R = r; } } } } return(R); }
private int FindAxis(double[] dir) { int r0 = 0; double d0 = double.MaxValue; foreach (PAxis Ax in Axes) { double v = PGeom.Dist2(dir, Ax.Dir); if (v < d0) { d0 = v; r0 = Ax.Id + 1; } v = PGeom.Dist2Rev(dir, Ax.Dir); if (v < d0) { d0 = v; r0 = -Ax.Id - 1; } } return(r0); }
internal int FindNearestAxis(double[] pt, bool qexact) { double tbest = qexact ? 0.999999 : -1; int res = 0; double ld = PGeom.DotProd(pt, pt); for (int i = 0; i < Axes.Length; i++) { double[] v = Axes[i].Dir; double x = PGeom.DotProd(pt, v) / Math.Sqrt(ld * PGeom.DotProd(v, v)); if (x > tbest) { res = i + 1; tbest = x; } if (x < -tbest) { res = -i - 1; tbest = -x; } } return(res); }
internal bool FindTwist(int nf, double[] pt, out int ax, out int tw) // 4D only { ax = Faces[nf].RefAxis; tw = 0; if (ax == 0) { return(false); } int iax = Math.Abs(ax) - 1; double[] actr = Axes[iax].Dir; double[] rtw = new double[Dim]; double l1 = PGeom.DotProd(pt, actr) / PGeom.DotProd(actr, actr); for (int i = 0; i < Dim; i++) { rtw[i] = pt[i] - l1 * actr[i]; } double tbest = -1; double[] p = new double[4]; for (int i = 0; i < Axes[iax].Twists.Length; i++) { double[] u = Axes[iax].Twists[i]; p[0] = actr[1] * (u[2] * u[7] - u[3] * u[6]) + actr[2] * (u[3] * u[5] - u[1] * u[7]) + actr[3] * (u[1] * u[6] - u[2] * u[5]); p[1] = actr[0] * (u[3] * u[6] - u[2] * u[7]) + actr[2] * (u[0] * u[7] - u[3] * u[4]) + actr[3] * (u[2] * u[4] - u[0] * u[6]); p[2] = actr[0] * (u[1] * u[7] - u[3] * u[5]) + actr[1] * (u[3] * u[4] - u[0] * u[7]) + actr[3] * (u[0] * u[5] - u[1] * u[4]); p[3] = actr[0] * (u[2] * u[5] - u[1] * u[6]) + actr[1] * (u[0] * u[6] - u[2] * u[4]) + actr[2] * (u[1] * u[4] - u[0] * u[5]); l1 = -PGeom.DotProd(p, rtw) / Math.Sqrt(PGeom.DotProd(p, p)); if (l1 < -tbest) { tbest = -l1; tw = -i - 1; } if (l1 > tbest) { tbest = l1; tw = i + 1; } } return(true); }
private int FindAxisInv(double[] dir, double[,] matr) { dir = PGeom.ApplyInvMatrix(matr, dir); return(FindAxis(dir)); }
internal int FindAxis(double[] dir, double[,] matr) { dir = PGeom.ApplyMatrix(matr, dir); return(FindAxis(dir)); }
private void FillFromStrings(string[] descr) { int naxis = 0; int caxis = 0; PBaseAxis ax = null; int state = 0; int nv; int fline = 0; QSimplified = false; try { while (state >= 0) { if (fline == descr.Length) { if (state != 7) { throw new Exception("Unexpected end"); } break; } string line = descr[fline++]; if (line == "" || line == null || line[0] == '#') { continue; } string[] str = line.Split(' ', '\t'); if (str.Length == 0 || str[0] == "" || str[0] == null) { continue; } string cmd = str[0].ToLowerInvariant(); switch (state) { case 0: if (cmd != "dim") { throw new Exception("'Dim' required"); } Dim = int.Parse(str[1]); break; case 1: if (cmd != "naxis") { throw new Exception("'NAxis' required"); } naxis = int.Parse(str[1]); BaseAxes = new PBaseAxis[naxis]; break; case 2: if (cmd != "faces") { throw new Exception("'Faces' required"); } nv = str.Length - 1; BaseFaces = new PBaseFace[nv]; for (int i = 0; i < nv; i++) { BaseFaces[i] = new PBaseFace(GetVector(str[i + 1], Dim)); } break; case 3: if (cmd == "simplified") { QSimplified = true; state--; break; } if (cmd != "group") { throw new Exception("'Group' required"); } nv = str.Length - 1; Group = new double[nv][]; for (int i = 0; i < nv; i++) { Group[i] = GetVector(str[i + 1], 2 * Dim); PGeom.GetOrder(Group[i]); } if (naxis == 0) { state = -2; } break; case 4: if (cmd != "axis") { throw new Exception("'Axis' required"); } ax = new PBaseAxis(GetVector(str[1], Dim)); break; case 5: if (cmd != "twists") { throw new Exception("'Twists' required"); } nv = str.Length - 1; ax.Twists = new PBaseTwist[nv]; for (int i = 0; i < nv; i++) { ax.Twists[i] = new PBaseTwist(GetVector(str[i + 1], 2 * Dim)); } break; case 6: if (cmd != "cuts") { throw new Exception("'Cuts' required"); } nv = str.Length - 1; ax.Cut = new double[nv]; for (int i = 0; i < nv; i++) { ax.Cut[i] = double.Parse(str[i + 1], CultureInfo.InvariantCulture); } ax.AdjustCuts(); BaseAxes[caxis++] = ax; ax = null; break; case 7: { if (cmd == "fixedmask") { BaseAxes[caxis - 1].FixedMask = int.Parse(str[1]); if (caxis == naxis) { state = -2; } else { state = 3; } break; } if (caxis != naxis) { state = 4; goto case 4; } state = -2; break; } } state++; } } catch (Exception e) { throw new Exception("Error: " + e.Message + " in line " + fline + ": " + (descr[fline] ?? "{null}")); } }
internal void SetStickers(LMesh M, CutNetwork CN, PAxis[] Axes, double[][] fctrs) { int dim = Pole.Length; NCutAxes = 0; int nax = Axes.Length; for (int i = 0; i < nax; i++) { if (AxisLayers[i] < 0) { NCutAxes++; } } CutAxes = new int[NCutAxes]; int d = 0; int rnk = 0; for (int u = 0; u < nax; u++) { if (AxisLayers[u] < 0) { CutAxes[d++] = u; } else { rnk += Axes[u].Base.GetRank(AxisLayers[u]); } } NStickers = CN.Nodes.Length; StickerMask = new byte[NStickers, NCutAxes]; StickerMesh = new PMesh[NStickers]; int nstk = 0; for (int i = 0; i < NStickers; i++) { PMesh xx = CN.GetPMesh(i); if (fctrs != null) { bool qg = false; foreach (double[] p in fctrs) { if (PGeom.VertEqual(p, xx.Ctr)) { qg = true; break; } } if (!qg) { continue; } } xx.FCtr = Pole; double[] ctr = xx.GetMCtr(); int rnk1 = rnk; for (int j = 0; j < NCutAxes; j++) { PAxis ax = Axes[CutAxes[j]]; double[] h = ax.Dir; double lh = PGeom.DotProd(h, h); double s = 0; for (int k = 0; k < dim; k++) { s += ctr[k] * h[k]; } s /= lh; int lv = ax.Base.NLayers - 1; for (int g = 0; g < lv; g++) { if (s > ax.Base.Cut[g]) { lv = g; break; } } rnk1 += ax.Base.GetRank(lv); StickerMask[nstk, j] = (byte)lv; } xx.Rank = rnk1; StickerMesh[nstk++] = xx; } if (nstk != NStickers) { PMesh[] stkm = new PMesh[nstk]; byte[,] stkmsk = new byte[nstk, NCutAxes]; for (int i = 0; i < nstk; i++) { stkm[i] = StickerMesh[i]; for (int j = 0; j < NCutAxes; j++) { stkmsk[i, j] = StickerMask[i, j]; } } StickerMask = stkmsk; StickerMesh = stkm; NStickers = nstk; } }
private void CutFaces() { double RMax = 0; foreach (PBaseFace F in BaseFaces) { RMax = Math.Max(RMax, PGeom.VLength(F.Pole)); } int minrank = int.MaxValue; foreach (PBaseFace F in BaseFaces) { CutNode face = CutNode.GenCube(Dim, RMax * Dim); double[] hpln = CutNetwork.GetPlane(F.Pole, 1); face.Split(1, hpln, false); face = face.ZeroNode; int opgen = 1; foreach (PFace FF in Faces) { if (F.Id != FF.Id) { hpln = CutNetwork.GetPlane(FF.Pole, 1); face.Split(++opgen, hpln, true); if (face.Status != CutNode.STAT_PLUS) { throw new Exception("Empty face: Id=" + F.Id); } } } int nff = face.Children.Length; double[][] ffpol = new double[nff][]; for (int i = 0; i < nff; i++) { ffpol[i] = face.Children[i].Pole; } F.FPoles = ffpol; LMesh m = new LMesh(Dim, true); face.FillLMesh(++opgen, m); m.CloseCtr(); F.FaceMesh = new PMesh(m); F.FaceMesh.FCtr = F.Pole; double[] verts = m.pts; int nverts = m.npts; CutNetwork CN = new CutNetwork(face, Dim, opgen); double[][] fctrs = null; if (QSimplified) { fctrs = CN.GetCtrs(); } F.AxisLayers = new int[Axes.Length]; for (int u = 0; u < Axes.Length; u++) { PAxis Ax = Axes[u]; double[] D = Ax.Dir; double lD = PGeom.Dist2(D, new double[Dim]); double smin = double.MaxValue, smax = double.MinValue; for (int i = 0; i < nverts; i++) { double v = 0; for (int j = 0; j < Dim; j++) { v += D[j] * verts[i * Dim + j]; } if (v < smin) { smin = v; } if (v > smax) { smax = v; } } smin /= lD; smax /= lD; bool cs = false, cc = false; int k = Ax.Base.NLayers - 1; for (int i = 0; i < Ax.Base.Cut.Length; i++) { double p = Ax.Base.Cut[i]; if (p >= smax - 0.0001) { continue; } if (!cs) { k = i; cs = true; } if (p <= smin + 0.0001) { break; } hpln = CutNetwork.GetPlane(Ax.Dir, p); CN.Split(hpln, false); cc = true; } if (cc) { k = -1; } F.AxisLayers[u] = k; } F.SetStickers(m, CN, Axes, fctrs); minrank = Math.Min(minrank, F.MinRank()); } foreach (PBaseFace F in BaseFaces) { F.SubRank(minrank); } }
internal PBaseFace(double[] pole) { Pole = pole; SMatrices = new ArrayList(); SMatrices.Add(PGeom.MatrixIdentity(pole.Length)); }
internal PFace(PFace src, double[] tw) { Base = src.Base; Pole = PGeom.ApplyTwist(tw, src.Pole); Matrix = PGeom.ApplyTwist(tw, src.Matrix); }
internal void InitPuzzle(Puzzle cube) { Cube = cube; int dim = Cube.Str.Dim; NF = Cube.Str.Faces.Length; NStk = Cube.Str.NStickers; SetColorsArray(null); StFaces = new StkMesh[NF]; FPoles = new double[NF][]; Stks = new StkMesh[NStk]; BPln = new bool[NF]; int[] vn = new int[100000 * 4]; lVN = 0; double[][][] FFPoles = new double[NF][][]; for (int i = 0; i < NF; i++) { PFace F = Cube.Str.Faces[i]; StFaces[i] = new StkMesh(F.Base.FaceMesh, i, F.Matrix); FPoles[i] = F.Pole; int fstk = F.FirstSticker; for (int j = 0; j < F.Base.NStickers; j++) { Stks[fstk + j] = new StkMesh(F.Base.StickerMesh[j], i, F.Matrix); Stks[fstk + j].FCtr = F.Pole; } double[][] baseFFP = F.Base.FPoles; FFPoles[i] = new double[baseFFP.Length][]; for (int j = 0; j < baseFFP.Length; j++) { FFPoles[i][j] = PGeom.ApplyMatrix(F.Matrix, baseFFP[j]); } } for (int i = 0; i < NF; i++) { StFaces[i].SetCoord(1, 1); } for (int i = 1; i < NF; i++) { for (int j = 0; j < i; j++) { double[][] pi = FFPoles[i], pj = FFPoles[j]; foreach (double[] vi in pi) { foreach (double[] vj in pj) { if (PtEq(vi, vj, dim)) { goto _1; } } } continue; _1: StkMesh Fi = StFaces[i], Fj = StFaces[j]; float[] fpi = Fi.Coords, fpj = Fj.Coords; for (int i1 = 0; i1 < fpi.Length; i1 += dim) { for (int j1 = 0; j1 < fpj.Length; j1 += dim) { if (PtEq(fpi, i1, fpj, j1, dim)) { vn[lVN++] = i; vn[lVN++] = i1; vn[lVN++] = j; vn[lVN++] = j1; break; } } } } } VertNetwork = new int[lVN]; Buffer.BlockCopy(vn, 0, VertNetwork, 0, lVN * sizeof(int)); }
internal PBaseTwist(double[] dir) { Dir = dir; Order = PGeom.GetOrder(Dir); }