// NOTE: The Group definitions in this file, and many of the comments, // came directly from the Mac version of Kali by Jeff Weeks. Thanks // to Jeff for his lucid programming style and copius comments! // mbp Mon Sep 16 17:06:26 1996 /** * The SymmetryGroup class holds the data for a particular symmetry * group. A symmetry group may be generated by * * *

* Kali always performs the generators in that order. Given a line * segment upon which the group is to act, first the line segment is * reflected (if a reflection is present), then the line and its * reflection are glide reflected (if a glide reflection is present), * then the images are rotated (if a rotation is present) and finally * all images are translated according to whatever translations are * present. * *

* Note: all the math happens in the * Panorama object; the SymmetryGroup * object just holds the group data. * * @see SymmetryGroups * @see Panorama */ class SymmetryGroup implements Constants { /** * The index of the group (value is one of the constants defined * Constants.java) */ public int index; /** * The name of the group (for debug printing, etc) */ public String name; /** * reflectionType has one of the values AXIS_NONE, AXIS_X0, * AXIS_X4, AXIS_Y0, or AXIS_Y4. If reflectionType != AXIS_NONE, * do a reflection about the specified axis. */ public int reflectionType; /** * If glideReflectionType != axis_none, do a glide reflection * a distance 1/2 along the specified axis. */ public int glideReflectionType; /** * rotationOrder gives the order of the rotation about * the origin if a rotation is present. Otherwise it's zero. */ public int rotationOrder; /** * numTranslations tells how many independent translations are * present. It will be 2 for a wallpaper group, 1 for a frieze * group, and 0 for a rosette group. The array "translations" * gives the translation vectors. */ public int numTranslations; public DVector[] translations; // [2] /** * The number of mirror segments (same as mirrorSegments.length). */ public int numMirrorSegments; // maximum is four /** * The locations of the mirror segments. NOTE: currently * Java Kali does not display these; they're included here * because they were present in the Mac version, and a future * version of Java Kali might display them. */ public Segment[] mirrorSegments; // [4] /** * XYZZYNOTE: currently * Java Kali does not display these; they're included here * because they were present in the Mac version, and a future * version of Java Kali might display them. */ /** * The number of glide segments (same as mirrorSegments.length). */ public int numGlideSegments; // maximum is two /** * The locations of the glide segments. */ public Segment[] glideSegments; // [2] /** * The number of gyration points (same as mirrorSegments.length). */ public int numGyrationPoints; // maximum is four /** * The locations of the gyration points. */ public DVector[] gyrationPoints; // [4] /** * Create a new SymmetryGroup object with the given data (and no * mirror segments, glide segments, or gyration points). */ public SymmetryGroup(int index, String name, int reflectionType, int glideReflectionType, int rotationOrder) { this.index = index; this.name = name; this.reflectionType = reflectionType; this.glideReflectionType = glideReflectionType; this.rotationOrder = rotationOrder; this.numTranslations = 0; this.translations = null; this.numMirrorSegments = 0; this.mirrorSegments = null; this.numGlideSegments = 0; this.glideSegments = null; this.numGyrationPoints = 0; this.gyrationPoints = null; } /** * Create a new SymmetryGroup object with the given data. */ public SymmetryGroup(int index, String name, int reflectionType, int glideReflectionType, int rotationOrder, DVector[] translations, Segment[] mirrorSegments, Segment[] glideSegments, DVector[] gyrationPoints) { this.index = index; this.name = name; this.reflectionType = reflectionType; this.glideReflectionType = glideReflectionType; this.rotationOrder = rotationOrder; this.translations = translations; if (translations != null) { this.numTranslations = translations.length; } else { this.numTranslations = 0; } this.mirrorSegments = mirrorSegments; if (mirrorSegments != null) { this.numMirrorSegments = mirrorSegments.length; } else { this.numMirrorSegments = 0; } this.glideSegments = glideSegments; if (glideSegments != null) { this.numGlideSegments = glideSegments.length; } else { this.numGlideSegments = 0; } this.gyrationPoints = gyrationPoints; if (gyrationPoints != null) { this.numGyrationPoints = gyrationPoints.length; } else { this.numGyrationPoints = 0; } } /** * Convert an axis integer to a string for printing */ private String axisString(int axis) { switch (axis) { case AXIS_NONE: return ("AXIS_NONE"); case AXIS_X0: return ("AXIS_X0"); case AXIS_X4: return ("AXIS_X4"); case AXIS_Y0: return ("AXIS_Y0"); case AXIS_Y4: return ("AXIS_Y4"); default: return ("???"); } } /** * Convert a SymmetryGroup to a string for printing */ public String toString() { return ("SymmetryGroup[" + axisString(reflectionType) + ", " + axisString(glideReflectionType) + ", " + rotationOrder + ", " + DVector.aString(translations) + ", " + Segment.aString(mirrorSegments) + ", " + Segment.aString(glideSegments) + ", " + DVector.aString(gyrationPoints) + "]"); } } /** * The SymmetryGroups (note the 's' on the end!) object holds a list * of all the groups used in the program (each entry in this list is * an instance of the SymmetryGroup (no 's' at the end) class. The * SymmetryGroups class is not meant to be instanced; just refer to * its group field and getCount() method. * * @see SymmetryGroup * @see Panorama */ class SymmetryGroups implements Constants { /** * The list of groups */ public static SymmetryGroup[] group = { // // wallpaper groups // new SymmetryGroup(GROUP_w2222, "2222", AXIS_NONE, AXIS_NONE, 2, DVector.array(1.0, 0.0, 0.0, 1.0), null, null, DVector.array(0.0, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5)), new SymmetryGroup(GROUP_w333, "333", AXIS_NONE, AXIS_NONE, 3, DVector.array(1.0, 0.0, 0.5, 0.5*ROOT3), null, null, DVector.array(0.0, 0.0, 0.5, 0.5/ROOT3, 0.5, -0.5/ROOT3)), new SymmetryGroup(GROUP_w442, "442", AXIS_NONE, AXIS_NONE, 4, DVector.array(1.0, 0.0, 0.0, 1.0), null, null, DVector.array(0.0, 0.0, 0.5, 0.0, 0.5, 0.5)), new SymmetryGroup(GROUP_w632, "632", AXIS_NONE, AXIS_NONE, 6, DVector.array(1.0, 0.0, 0.5, 0.5*ROOT3), null, null, DVector.array(0.0, 0.0, 0.5, 0.0, 0.5, 0.5/ROOT3)), new SymmetryGroup(GROUP_wx2222, "*2222", AXIS_X0, AXIS_NONE, 2, DVector.array(1.0, 0.0, 0.0, 1.0), Segment.array(0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0), null, null), new SymmetryGroup(GROUP_wx333, "*333", AXIS_X0, AXIS_NONE, 3, DVector.array(1.0, 0.0, 0.5, 0.5*ROOT3), Segment.array(0.0, 0.0, 0.5, -0.5/ROOT3, 0.5, -0.5/ROOT3, 0.5, 0.5/ROOT3, 0.5, 0.5/ROOT3, 0.0, 0.0), null, null), new SymmetryGroup(GROUP_wx442, "*442", AXIS_X0, AXIS_NONE, 4, DVector.array(1.0, 0.0, 0.0, 1.0), Segment.array(0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, 0.0), null, null), new SymmetryGroup(GROUP_wx632, "*632", AXIS_X0, AXIS_NONE, 6, DVector.array(1.0, 0.0, 0.5, 0.5*ROOT3), Segment.array(0.0, 0.0, 0.25, 0.25*ROOT3, 0.25, 0.25*ROOT3, 0.0, 1.0/ROOT3, 0.0, 1.0/ROOT3, 0.0, 0.0), null, null), new SymmetryGroup(GROUP_w4x2, "4*2", AXIS_X4, AXIS_NONE, 4, DVector.array(0.5, 0.5, 0.5, -0.5), Segment.array(-0.25, 0.25, 0.25, 0.25), null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_w3x3, "3*3", AXIS_X0, AXIS_NONE, 3, DVector.array(0.5*ROOT3, 0.5, 0.0, 1.0), Segment.array(0.0, 0.0, 0.25*ROOT3, 0.25, 0.0, 0.0, 0.25*ROOT3, -0.25), null, DVector.array(1.0/ROOT3, 0.0)), // 2x22 // // This group is easily defined by a reflection followed by an // order two rotation. The only problem is that the translations // are then at odd angles, making it hard to deform the shape of // the fundamental domain. So instead we throw an "unnecessary" // glide reflection into the definition: it makes the fundamental // domain twice as big, and makes the translations orthogonal to // one another. // // This all makes more sense if you draw a picture. Start with a // rectangle with mirrored edges to represent *2222, and mod out // by a half turn about its center to get 2*22. Bisect the // rectangle to get a fundamental domain for the orbifold (I cut // it with a diagonal, but any bisection will do). Mark the // origin at the center of the rectangle, and draw a dozen or so // of its nearest translates in the universal cover. Color in // your original fundamental domain (half the original rectangle). // Then color its reflection in the line x = (width of // rectangle)/2. Then take the union of the two colored regions // and color their image under a glide reflection a distance // (height of rectangle)/2 along the y-axis. Finally, take the // union of all that and color its image under a half turn about // the origin. Your final colored region will tile the plane // under the action of the generators x -> x + 2*width, y -> y + // 2*height. The point of all this is that we can do the initial // calculation for a square, and then stretch it after the fact. // new SymmetryGroup(GROUP_w2x22, "2*22", AXIS_X4, AXIS_X0, 2, DVector.array(1.0, 0.0, 0.0, 1.0), Segment.array(0.25, -0.25, 0.25, 0.25, -0.25, -0.25, 0.25, -0.25), Segment.array(0.0, 0.0, 0.0, -0.25), DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_w22x, "22*", AXIS_X4, AXIS_NONE, 2, DVector.array(1.0, 0.0, 0.0, 1.0), Segment.array(0.25, -0.5, 0.25, 0.5), null, DVector.array(0.0, 0.0, 0.0, 0.5)), new SymmetryGroup(GROUP_wxx, "**", AXIS_X0, AXIS_NONE, 1, DVector.array(1.0, 0.0, 0.0, 1.0), Segment.array(0.0, -0.5, 0.0, 0.5, 0.5, -0.5, 0.5, 0.5), null, null), new SymmetryGroup(GROUP_wxo, "*o", AXIS_X0, AXIS_X4, 1, DVector.array(1.0, 0.0, 0.0, 1.0), Segment.array(0.0, 0.0, 0.0, 1.0), Segment.array(0.25, 0.0, 0.25, 0.5), null), new SymmetryGroup(GROUP_woo, "oo", AXIS_NONE, AXIS_X0, 1, DVector.array(1.0, 0.0, 0.0, 1.0), null, Segment.array(0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.5, 0.5), null), new SymmetryGroup(GROUP_w22o, "22o", AXIS_NONE, AXIS_X4, 2, DVector.array(1.0, 0.0, 0.0, 1.0), null, Segment.array(0.25, 0.0, 0.25, 0.5), DVector.array(0.0, 0.0, 0.0, 0.5)), new SymmetryGroup(GROUP_wt, // torus "0", AXIS_NONE, AXIS_NONE, 1, DVector.array(1.0, 0.0, 0.0, 1.0), null, null, null), // // frieze groups // new SymmetryGroup(GROUP_fii, "oooo", AXIS_NONE, AXIS_NONE, 1, DVector.array(1.0, 0.0), null, null, null), new SymmetryGroup(GROUP_fix, "oo*", AXIS_Y0, AXIS_NONE, 1, DVector.array(1.0, 0.0), Segment.array(0.0, 0.0, 1.0, 0.0), null, null), new SymmetryGroup(GROUP_fxii, "*oooo", AXIS_X0, AXIS_NONE, 1, DVector.array(1.0, 0.0), Segment.array(0.0, -1.0, 0.0, 1.0, 0.5, -1.0, 0.5, 1.0), null, null), new SymmetryGroup(GROUP_f22i, "22oo", AXIS_NONE, AXIS_NONE, 2, DVector.array(1.0, 0.0), null, null, DVector.array(0.0, 0.0, 0.5, 0.0)), new SymmetryGroup(GROUP_fx22i, "*22oo", AXIS_Y0, AXIS_NONE, 2, DVector.array(1.0, 0.0), Segment.array(0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.5, 0.0, 0.5, 1.0), null, null), new SymmetryGroup(GROUP_f2xi, "2*oo", AXIS_X4, AXIS_NONE, 2, DVector.array(1.0, 0.0), Segment.array(0.25, -1.0, 0.25, 1.0), null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_fio, "ooo", AXIS_NONE, AXIS_Y0, 1, DVector.array(1.0, 0.0), null, Segment.array(0.0, 0.0, 0.5, 0.0), null), // // rosette groups // new SymmetryGroup(GROUP_r1, "1", AXIS_NONE, AXIS_NONE, 1, null, null, null, null), new SymmetryGroup(GROUP_r2, "2", AXIS_NONE, AXIS_NONE, 2, null, null, null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_r3, "3", AXIS_NONE, AXIS_NONE, 3, null, null, null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_r4, "4", AXIS_NONE, AXIS_NONE, 4, null, null, null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_r5, "5", AXIS_NONE, AXIS_NONE, 5, null, null, null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_r6, "6", AXIS_NONE, AXIS_NONE, 6, null, null, null, DVector.array(0.0, 0.0)), new SymmetryGroup(GROUP_rx1, "*1", AXIS_X0, AXIS_NONE, 1, null, Segment.array(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0), null, null), new SymmetryGroup(GROUP_rx2, "*2", AXIS_X0, AXIS_NONE, 2, null, Segment.array(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0), null, null), new SymmetryGroup(GROUP_rx3, "*3", AXIS_X0, AXIS_NONE, 3, null, Segment.array(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0), null, null), new SymmetryGroup(GROUP_rx4, "*4", AXIS_X0, AXIS_NONE, 4, null, Segment.array(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5*ROOT2, 0.5*ROOT2), null, null), new SymmetryGroup(GROUP_rx5, "*5", AXIS_X0, AXIS_NONE, 5, null, Segment.array(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0), null, null), new SymmetryGroup(GROUP_rx6, "*6", AXIS_X0, AXIS_NONE, 6, null, Segment.array(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5*ROOT3), null, null), }; /** * Return the number of groups in the list. */ public static int getCount() { return group.length; } }