package com.jpl.games.model; import com.jpl.games.math.Rotations; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javafx.geometry.Point3D; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.MeshView; import javafx.scene.shape.TriangleMesh; import javafx.scene.transform.Affine; import javafx.scene.transform.Rotate; import javafx.scene.transform.Scale; import javafx.scene.transform.Translate; /** * * @author jpereda, April 2014 - @JPeredaDnr */ public class Utils { // suitable movements to scramble the cube private static final List<String> movements = Arrays.asList("F", "Fi", "F2", "R", "Ri", "R2", "B", "Bi", "B2", "L", "Li", "L2", "U", "Ui", "U2", "D", "Di", "D2"); // 24 suitable orientations for solved cube private static final List<String> orientations=Arrays.asList("V-V","V-Y","V-Yi","V-Y2", "X-V","X-Z","X-Zi","X-Z2", "Xi-V","Xi-Z","Xi-Zi", "X2-V","X2-Z","X2-Zi", "X-Y","X-Yi","X-Y2", "Xi-Y","Xi-Yi","X2-Y","X2-Yi", "Z-V","Zi-V","Z2-V"); public static final List<String> getMovements() { return movements; } public static final List<String> getOrientations() { return orientations; } public static final double radMinimum=10d, radClick=30d; public static Affine getAffine(double dimCube, double d0, boolean bFaceArrow, String face){ Affine aff; double d=2d*dimCube/3d; if(!bFaceArrow){ aff=new Affine(new Scale(80,80,50)); aff.append(new Translate(-d0,-d0,d0)); } else { aff=new Affine(new Scale(3,3,3)); aff.append(new Translate(0,-d0,0)); } switch(face){ case "F": case "Fi": aff.prepend(new Rotate(face.equals("F")?90:-90,Rotate.X_AXIS)); aff.prepend(new Rotate(face.equals("F")?45:-45,Rotate.Z_AXIS)); aff.prepend(new Translate(0,0,dimCube/2d)); break; case "B": case "Bi": aff.prepend(new Rotate(face.equals("Bi")?90:-90,Rotate.X_AXIS)); aff.prepend(new Rotate(face.equals("Bi")?45:-45,Rotate.Z_AXIS)); aff.prepend(new Translate(0,0,-dimCube/2d)); break; case "R": case "Ri": aff.prepend(new Rotate(face.equals("Ri")?90:-90,Rotate.Z_AXIS)); aff.prepend(new Rotate(face.equals("Ri")?45:-45,Rotate.X_AXIS)); aff.prepend(new Translate(dimCube/2d,0,0)); break; case "L": case "Li": aff.prepend(new Rotate(face.equals("L")?90:-90,Rotate.Z_AXIS)); aff.prepend(new Rotate(face.equals("L")?45:-45,Rotate.X_AXIS)); aff.prepend(new Translate(-dimCube/2d,0,0)); break; case "U": case "Ui": aff.prepend(new Rotate(face.equals("Ui")?180:0,Rotate.Z_AXIS)); aff.prepend(new Rotate(face.equals("Ui")?45:-45,Rotate.Y_AXIS)); aff.prepend(new Translate(0,dimCube/2d,0)); break; case "D": case "Di": aff.prepend(new Rotate(face.equals("D")?180:0,Rotate.Z_AXIS)); aff.prepend(new Rotate(face.equals("D")?45:-45,Rotate.Y_AXIS)); aff.prepend(new Translate(0,-dimCube/2d,0)); break; case "Z": case "Zi": aff.prepend(new Rotate(face.equals("Zi")?180:0,Rotate.Y_AXIS)); aff.prepend(new Rotate(face.equals("Zi")?45:-45,Rotate.Z_AXIS)); aff.prepend(new Translate(0,0,d)); break; case "X": case "Xi": aff.prepend(new Rotate(face.equals("X")?90:-90,Rotate.Y_AXIS)); aff.prepend(new Rotate(face.equals("Xi")?45:-45,Rotate.X_AXIS)); aff.prepend(new Translate(d,0,0)); break; case "Y": case "Yi": aff.prepend(new Rotate(face.equals("Yi")?90:-90,Rotate.X_AXIS)); aff.prepend(new Rotate(face.equals("Yi")?45:-45,Rotate.Y_AXIS)); aff.prepend(new Translate(0,d,0)); break; } return aff; } public static PhongMaterial getMaterial(String face){ PhongMaterial arrowMat = new PhongMaterial(); arrowMat.setSpecularColor(Color.WHITESMOKE); Color color=Color.WHITE; switch(face){ case "F": case "Fi": color=Color.BLUE.brighter(); break; case "B": case "Bi": color=Color.BLUE.brighter(); break; case "R": case "Ri": color=Color.RED.brighter(); break; case "L": case "Li": color=Color.RED.brighter(); break; case "U": case "Ui": color=Color.FORESTGREEN.brighter(); break; case "D": case "Di": color=Color.FORESTGREEN.brighter(); break; case "Z": case "Zi": color=Color.BLUE.brighter(); break; case "X": case "Xi": color=Color.RED.brighter(); break; case "Y": case "Yi": color=Color.FORESTGREEN.brighter(); break; } arrowMat.setDiffuseColor(color); return arrowMat; } public static Point3D getAxis(String face){ Point3D p=new Point3D(0,0,0); switch(face.substring(0,1)){ case "L": case "M": p=new Point3D(-1,0,0); break; case "R": p=new Point3D(1,0,0); break; case "U": p=new Point3D(0,1,0); break; case "E": case "D": p=new Point3D(0,-1,0); break; case "F": case "S": p=new Point3D(0,0,1); break; case "B": p=new Point3D(0,0,-1); break; case "X": p=new Point3D(1,0,0); break; case "Y": p=new Point3D(0,1,0); break; case "Z": p=new Point3D(0,0,1); break; } return p; } public static int getCenter(String face){ int c=0; switch(face.substring(0,1)){ case "L": c=12; break; case "M": c=13; break; case "R": c=14; break; case "U": c=10; break; case "E": c=13; break; case "D": c=16; break; case "F": c=4; break; case "S": c=13; break; case "B": c=22; break; } return c; } public static String getPickedRotation(int cubie, MeshView mesh){ Point3D normal=getMeshNormal(mesh); String rots=""; // Rx-Ry switch(cubie){ case 0: rots=(normal.getZ()>0.99)?"Ui-Li":((normal.getX()<-0.99)?"Ui-F":((normal.getY()>0.99)?"Ui-Li":"")); break; case 1: rots=(normal.getZ()>0.99)?"F-Mi":((normal.getY()>0.99)?"Ui-Mi":""); // between L and R, as L break; case 2: rots=(normal.getZ()>0.99)?"Ui-R":((normal.getX()>0.99)?"Ui-Fi":((normal.getY()>0.99)?"Ui-R":"")); break; case 3: rots=(normal.getZ()>0.99)?"E-F":((normal.getX()<-0.99)?"E-Li":""); // between U and D, as D break; case 4: rots=(normal.getZ()>0.99)?"Yi-X":""; break; case 5: rots=(normal.getZ()>0.99)?"E-Fi":((normal.getX()>0.99)?"E-R":""); // between U and D, as D break; case 6: rots=(normal.getZ()>0.99)?"D-Li":((normal.getX()<-0.99)?"D-F":((normal.getY()<-0.99)?"D-Li":"")); break; case 7: rots=(normal.getZ()>0.99)?"Fi-Mi":((normal.getY()<-0.99)?"Fi-Mi":""); // between L and R, as L break; case 8: rots=(normal.getZ()>0.99)?"D-R":((normal.getX()>0.99)?"D-Fi":((normal.getY()<-0.99)?"D-R":"")); break; case 9: rots=(normal.getY()>0.99)?"S-U":((normal.getX()<-0.99)?"L-S":""); // between U and D, as D break; case 10: rots=(normal.getY()>0.99)?"Z-X":""; break; case 11: rots=(normal.getY()>0.99)?"S-Ui":((normal.getX()>0.99)?"R-Si":""); // between U and D, as D break; case 12: rots=(normal.getX()<-0.99)?"Yi-Z":""; break; case 14: rots=(normal.getX()>0.99)?"Yi-Zi":""; break; case 15: rots=(normal.getY()<-0.99)?"D-S":((normal.getX()<-0.99)?"Li-S":""); // between U and D, as D break; case 16: rots=(normal.getY()<-0.99)?"Zi-X":""; break; case 17: rots=(normal.getY()<-0.99)?"D-S":((normal.getX()>0.99)?"Ri-Si":""); // between U and D, as D break; case 18: rots=(normal.getZ()<-0.99)?"Ui-L":((normal.getX()<-0.99)?"Ui-Bi":((normal.getY()>0.99)?"Ui-L":"")); break; case 19: rots=(normal.getZ()<-0.99)?"B-M":((normal.getY()>0.99)?"U-M":""); // between L and R, as L break; case 20: rots=(normal.getZ()<-0.99)?"Ui-Ri":((normal.getX()>0.99)?"Ui-B":((normal.getY()>0.99)?"Ui-Ri":"")); break; case 21: rots=(normal.getZ()<-0.99)?"E-Bi":((normal.getX()<-0.99)?"E-L":""); // between U and D, as D break; case 22: rots=(normal.getZ()<-0.99)?"Yi-Xi":""; break; case 23: rots=(normal.getZ()<-0.99)?"E-B":((normal.getX()>0.99)?"E-Ri":""); // between U and D, as D break; case 24: rots=(normal.getZ()<-0.99)?"D-L":((normal.getX()<-0.99)?"D-Bi":((normal.getY()<-0.99)?"D-L":"")); break; case 25: rots=(normal.getZ()<-0.99)?"Bi-M":((normal.getY()<-0.99)?"Bi-M":""); // between L and R, as L break; case 26: rots=(normal.getZ()<-0.99)?"D-Ri":((normal.getX()>0.99)?"D-B":((normal.getY()<-0.99)?"D-B":"")); break; } return rots; } private static Point3D getMeshNormal(MeshView mesh){ TriangleMesh tm=(TriangleMesh)mesh.getMesh(); float[] fPoints=new float[tm.getPoints().size()]; tm.getPoints().toArray(fPoints); Point3D BA=new Point3D(fPoints[3]-fPoints[0],fPoints[4]-fPoints[1],fPoints[5]-fPoints[2]); Point3D CA=new Point3D(fPoints[6]-fPoints[0],fPoints[7]-fPoints[1],fPoints[8]-fPoints[2]); Point3D normal=BA.crossProduct(CA); Affine a=new Affine(mesh.getTransforms().get(0)); return a.transform(normal.normalize()); } public static String getRightRotation(Point3D p, String selFaces){ double radius=p.magnitude(); double angle=Math.atan2(p.getY(),p.getX()); String face=""; if(radius>=radMinimum && selFaces.contains("-") && selFaces.split("-").length==2){ String[] faces=selFaces.split("-"); // select rotation if p.getX>p.getY if(-Math.PI/4d<=angle && angle<Math.PI/4d){ // X face=faces[0]; } else if(Math.PI/4d<=angle && angle<3d*Math.PI/4d){ // Y face=faces[1]; } else if((3d*Math.PI/4d<=angle && angle<=Math.PI) || (-Math.PI<=angle && angle<-3d*Math.PI/4d)){ // -X face=reverseRotation(faces[0]); } else { //-Y face=reverseRotation(faces[1]); } System.out.println("face: "+face); } else if(!face.isEmpty() && radius<radMinimum){ // reset previous face face=""; } return face; } public static String reverseRotation(String rot){ if(rot.endsWith("i")){ return rot.substring(0,1); } return rot.concat("i"); } public static boolean checkOrientation(String r, List<Integer> order){ Rotations rot=new Rotations(); for(String s:r.split("-")){ if(s.contains("2")){ rot.turn(s.substring(0,1)); rot.turn(s.substring(0,1)); } else { rot.turn(s); } } return order.equals(rot.getCube()); } public static boolean checkSolution(List<Integer> order) { return Utils.getOrientations().parallelStream() .filter(r->Utils.checkOrientation(r,order)).findAny().isPresent(); } public static ArrayList<String> unifyNotation(String list) { List<String> asList = Arrays.asList(list.replaceAll("’", "i").replaceAll("'", "i").split(" ")); ArrayList<String> sequence = new ArrayList<>(); asList.stream().forEach(s -> { if (s.contains("2")) { sequence.add(s.substring(0, 1)); sequence.add(s.substring(0, 1)); } else if (s.length() == 1 && s.matches("[a-z]")) { sequence.add(s.toUpperCase().concat("i")); } else { sequence.add(s); } }); return sequence; } }