summaryrefslogtreecommitdiffstats
path: root/hacks/glx/polyhedra.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/polyhedra.c')
-rw-r--r--hacks/glx/polyhedra.c2458
1 files changed, 0 insertions, 2458 deletions
diff --git a/hacks/glx/polyhedra.c b/hacks/glx/polyhedra.c
deleted file mode 100644
index 98e6891..0000000
--- a/hacks/glx/polyhedra.c
+++ /dev/null
@@ -1,2458 +0,0 @@
-/*****************************************************************************
- * #ident "Id: main.c,v 3.27 2002-01-06 16:23:01+02 rl Exp "
- * kaleido
- *
- * Kaleidoscopic construction of uniform polyhedra
- * Copyright (c) 1991-2002 Dr. Zvi Har'El <rl@math.technion.ac.il>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by
- * Dr. Zvi Har'El (http://www.math.technion.ac.il/~rl/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the author be held liable for any
- * damages arising from the use of this software.
- *
- * Author:
- * Dr. Zvi Har'El,
- * Deptartment of Mathematics,
- * Technion, Israel Institue of Technology,
- * Haifa 32000, Israel.
- * E-Mail: rl@math.technion.ac.il
- *
- * ftp://ftp.math.technion.ac.il/kaleido/
- * http://www.mathconsult.ch/showroom/unipoly/
- *
- * Adapted for xscreensaver by Jamie Zawinski <jwz@jwz.org> 25-Apr-2004
- *
- *****************************************************************************
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <math.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include "polyhedra.h"
-
-extern const char *progname;
-
-#ifndef MAXLONG
-#define MAXLONG 0x7FFFFFFF
-#endif
-#ifndef MAXDIGITS
-#define MAXDIGITS 10 /* (int)log10((double)MAXLONG) + 1 */
-#endif
-
-#ifndef DBL_EPSILON
-#define DBL_EPSILON 2.2204460492503131e-16
-#endif
-#define BIG_EPSILON 3e-2
-#define AZ M_PI/7 /* axis azimuth */
-#define EL M_PI/17 /* axis elevation */
-
-#define Err(x) do {\
- fprintf (stderr, "%s: %s\n", progname, (x)); \
- exit (1); \
- } while(0)
-
-#define Free(lvalue) do {\
- if (lvalue) {\
- free((char*) lvalue);\
- lvalue=0;\
- }\
- } while(0)
-
-#define Matfree(lvalue,n) do {\
- if (lvalue) \
- matfree((char*) lvalue, n);\
- lvalue=0;\
- } while(0)
-
-#define Malloc(lvalue,n,type) do {\
- if (!(lvalue = (type*) calloc((n), sizeof(type)))) \
- abort();\
- } while(0)
-
-#define Realloc(lvalue,n,type) do {\
- if (!(lvalue = (type*) realloc(lvalue, (n) * sizeof(type)))) \
- abort();\
- } while(0)
-
-#define Calloc(lvalue,n,type) do {\
- if (!(lvalue = (type*) calloc(n, sizeof(type))))\
- abort();\
- } while(0)
-
-#define Matalloc(lvalue,n,m,type) do {\
- if (!(lvalue = (type**) matalloc(n, (m) * sizeof(type))))\
- abort();\
- } while(0)
-
-#define Sprintfrac(lvalue,x) do {\
- if (!(lvalue=sprintfrac(x)))\
- return 0;\
- } while(0)
-
-#define numerator(x) (frac(x), frax.n)
-#define denominator(x) (frac(x), frax.d)
-#define compl(x) (frac(x), (double) frax.n / (frax.n-frax.d))
-
-typedef struct {
- double x, y, z;
-} Vector;
-
-typedef struct {
- /* NOTE: some of the int's can be replaced by short's, char's,
- or even bit fields, at the expense of readability!!!*/
- int index; /* index to the standard list, the array uniform[] */
- int N; /* number of faces types (atmost 5)*/
- int M; /* vertex valency (may be big for dihedral polyhedra) */
- int V; /* vertex count */
- int E; /* edge count */
- int F; /* face count */
- int D; /* density */
- int chi; /* Euler characteristic */
- int g; /* order of symmetry group */
- int K; /* symmetry type: D=2, T=3, O=4, I=5 */
- int hemi;/* flag hemi polyhedron */
- int onesided;/* flag onesided polyhedron */
- int even; /* removed face in pqr| */
- int *Fi; /* face counts by type (array N)*/
- int *rot; /* vertex configuration (array M of 0..N-1) */
- int *snub; /* snub triangle configuration (array M of 0..1) */
- int *firstrot; /* temporary for vertex generation (array V) */
- int *anti; /* temporary for direction of ideal vertices (array E) */
- int *ftype; /* face types (array F) */
- int **e; /* edges (matrix 2 x E of 0..V-1)*/
- int **dual_e; /* dual edges (matrix 2 x E of 0..F-1)*/
- int **incid; /* vertex-face incidence (matrix M x V of 0..F-1)*/
- int **adj; /* vertex-vertex adjacency (matrix M x V of 0..V-1)*/
- double p[4]; /* p, q and r; |=0 */
- double minr; /* smallest nonzero inradius */
- double gon; /* basis type for dihedral polyhedra */
- double *n; /* number of side of a face of each type (array N) */
- double *m; /* number of faces at a vertex of each type (array N) */
- double *gamma; /* fundamental angles in radians (array N) */
- char *polyform; /* printable Wythoff symbol */
- char *config; /* printable vertex configuration */
- char *group; /* printable group name */
- char *name; /* name, standard or manifuctured */
- char *dual_name; /* dual name, standard or manifuctured */
- char *class;
- char *dual_class;
- Vector *v; /* vertex coordinates (array V) */
- Vector *f; /* face coordinates (array F)*/
-} Polyhedron;
-
-typedef struct {
- long n,d;
-} Fraction;
-
-static Polyhedron *polyalloc(void);
-static Vector rotate(Vector vertex, Vector axis, double angle);
-
-static Vector sum3(Vector a, Vector b, Vector c);
-static Vector scale(double k, Vector a);
-static Vector sum(Vector a, Vector b);
-static Vector diff(Vector a, Vector b);
-static Vector pole (double r, Vector a, Vector b, Vector c);
-static Vector cross(Vector a, Vector b);
-static double dot(Vector a, Vector b);
-static int same(Vector a, Vector b, double epsilon);
-
-static char *sprintfrac(double x);
-
-static void frac(double x);
-static void matfree(void *mat, int rows);
-static void *matalloc(int rows, int row_size);
-
-static Fraction frax;
-
-
-static const struct {
- char *Wythoff, *name, *dual, *group, *class, *dual_class;
- short Coxeter, Wenninger;
-} uniform[] = {
-
- /****************************************************************************
- * Dihedral Schwarz Triangles (D5 only)
- ***************************************************************************/
-
- /* 0 */ {"2 5|2", "Pentagonal Prism",
- "Pentagonal Dipyramid",
- "Dihedral (D[1/5])",
- "",
- "",
- 0, 0},
-
- /* 2 */ {"|2 2 5", "Pentagonal Antiprism",
- "Pentagonal Deltohedron",
- "Dihedral (D[1/5])",
- "",
- "",
- 0, 0},
- /* (2 2 5/2) (D2/5) */
- /* 4 */ {"2 5/2|2", "Pentagrammic Prism",
- "Pentagrammic Dipyramid",
- "Dihedral (D[2/5])",
- "",
- "",
- 0, 0},
-
- /* 6 */ {"|2 2 5/2", "Pentagrammic Antiprism",
- "Pentagrammic Deltohedron",
- "Dihedral (D[2/5])",
- "",
- "",
- 0, 0},
- /* (5/3 2 2) (D3/5) */
-
- /* 8 */ {"|2 2 5/3", "Pentagrammic Crossed Antiprism",
- "Pentagrammic Concave Deltohedron",
- "Dihedral (D[3/5])",
- "",
- "",
- 0, 0},
-
- /****************************************************************************
- * Tetrahedral
- ***************************************************************************/
-
- /* (2 3 3) (T1) */
- /* 10 */ {"3|2 3", "Tetrahedron",
- "Tetrahedron",
- "Tetrahedral (T[1])",
- "Platonic Solid",
- "Platonic Solid",
- 15, 1},
-
- /* 12 */ {"2 3|3", "Truncated Tetrahedron",
- "Triakistetrahedron",
- "Tetrahedral (T[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 16, 6},
- /* (3/2 3 3) (T2) */
- /* 14 */ {"3/2 3|3", "Octahemioctahedron",
- "Octahemioctacron",
- "Tetrahedral (T[2])",
- "",
- "",
- 37, 68},
-
- /* (3/2 2 3) (T3) */
- /* 16 */ {"3/2 3|2", "Tetrahemihexahedron",
- "Tetrahemihexacron",
- "Tetrahedral (T[3])",
- "",
- "",
- 36, 67},
-
- /****************************************************************************
- * Octahedral
- ***************************************************************************/
-
- /* (2 3 4) (O1) */
- /* 18 */ {"4|2 3", "Octahedron",
- "Cube",
- "Octahedral (O[1])",
- "Platonic Solid",
- "Platonic Solid",
- 17, 2},
-
- /* 20 */ {"3|2 4", "Cube",
- "Octahedron",
- "Octahedral (O[1])",
- "Platonic Solid",
- "Platonic Solid",
- 18, 3},
-
- /* 22 */ {"2|3 4", "Cuboctahedron",
- "Rhombic Dodecahedron",
- "Octahedral (O[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 19, 11},
-
- /* 24 */ {"2 4|3", "Truncated Octahedron",
- "Tetrakishexahedron",
- "Octahedral (O[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 20, 7},
-
- /* 26 */ {"2 3|4", "Truncated Cube",
- "Triakisoctahedron",
- "Octahedral (O[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 21, 8},
-
- /* 28 */ {"3 4|2", "Rhombicuboctahedron",
- "Deltoidal Icositetrahedron",
- "Octahedral (O[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 22, 13},
-
- /* 30 */ {"2 3 4|", "Truncated Cuboctahedron",
- "Disdyakisdodecahedron",
- "Octahedral (O[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 23, 15},
-
- /* 32, 33, 66, and 67 are chiral, existing in both left and right handed
- (enantiomeric) forms, so it would make sense to display both versions.
- */
-
- /* 32 */ {"|2 3 4", "Snub Cube",
- "Pentagonal Icositetrahedron",
- "Octahedral (O[1]), Chiral",
- "Archimedean Solid",
- "Catalan Solid",
- 24, 17},
- /* (3/2 4 4) (O2b) */
-
- /* 34 */ {"3/2 4|4", "Small Cubicuboctahedron",
- "Small Hexacronic Icositetrahedron",
- "Octahedral (O[2b])",
- "",
- "",
- 38, 69},
- /* (4/3 3 4) (O4) */
-
- /* 36 */ {"3 4|4/3", "Great Cubicuboctahedron",
- "Great Hexacronic Icositetrahedron",
- "Octahedral (O[4])",
- "",
- "",
- 50, 77},
-
- /* 38 */ {"4/3 4|3", "Cubohemioctahedron",
- "Hexahemioctacron",
- "Octahedral (O[4])",
- "",
- "",
- 51, 78},
-
- /* 40 */ {"4/3 3 4|", "Cubitruncated Cuboctahedron",
- "Tetradyakishexahedron",
- "Octahedral (O[4])",
- "",
- "",
- 52, 79},
- /* (3/2 2 4) (O5) */
-
- /* 42 */ {"3/2 4|2", "Great Rhombicuboctahedron",
- "Great Deltoidal Icositetrahedron",
- "Octahedral (O[5])",
- "",
- "",
- 59, 85},
-
- /* 44 */ {"3/2 2 4|", "Small Rhombihexahedron",
- "Small Rhombihexacron",
- "Octahedral (O[5])",
- "",
- "",
- 60, 86},
- /* (4/3 2 3) (O7) */
-
- /* 46 */ {"2 3|4/3", "Stellated Truncated Hexahedron",
- "Great Triakisoctahedron",
- "Octahedral (O[7])",
- "",
- "",
- 66, 92},
-
- /* 48 */ {"4/3 2 3|", "Great Truncated Cuboctahedron",
- "Great Disdyakisdodecahedron",
- "Octahedral (O[7])",
- "",
- "",
- 67, 93},
- /* (4/3 3/2 2) (O11) */
-
- /* 50 */ {"4/3 3/2 2|", "Great Rhombihexahedron",
- "Great Rhombihexacron",
- "Octahedral (O[11])",
- "",
- "",
- 82, 103},
-
- /****************************************************************************
- * Icosahedral
- ***************************************************************************/
-
- /* (2 3 5) (I1) */
- /* 52 */ {"5|2 3", "Icosahedron",
- "Dodecahedron",
- "Icosahedral (I[1])",
- "Platonic Solid",
- "Platonic Solid",
- 25, 4},
-
- /* 54 */ {"3|2 5", "Dodecahedron",
- "Icosahedron",
- "Icosahedral (I[1])",
- "Platonic Solid",
- "Platonic Solid",
- 26, 5},
-
- /* 56 */ {"2|3 5", "Icosidodecahedron",
- "Rhombic Triacontahedron",
- "Icosahedral (I[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 28, 12},
-
- /* 58 */ {"2 5|3", "Truncated Icosahedron",
- "Pentakisdodecahedron",
- "Icosahedral (I[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 27, 9},
-
- /* 60 */ {"2 3|5", "Truncated Dodecahedron",
- "Triakisicosahedron",
- "Icosahedral (I[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 29, 10},
-
- /* 62 */ {"3 5|2", "Rhombicosidodecahedron",
- "Deltoidal Hexecontahedron",
- "Icosahedral (I[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 30, 14},
-
- /* 64 */ {"2 3 5|", "Truncated Icosidodecahedron",
- "Disdyakistriacontahedron",
- "Icosahedral (I[1])",
- "Archimedean Solid",
- "Catalan Solid",
- 31, 16},
-
- /* 32, 33, 66, and 67 are chiral, existing in both left and right handed
- (enantiomeric) forms, so it would make sense to display both versions.
- */
-
- /* 66 */ {"|2 3 5", "Snub Dodecahedron",
- "Pentagonal Hexecontahedron",
- "Icosahedral (I[1]), Chiral",
- "Archimedean Solid",
- "Catalan Solid",
- 32, 18},
- /* (5/2 3 3) (I2a) */
-
- /* 68 */ {"3|5/2 3", "Small Ditrigonal Icosidodecahedron",
- "Small Triambic Icosahedron",
- "Icosahedral (I[2a])",
- "",
- "",
- 39, 70},
-
- /* 70 */ {"5/2 3|3", "Small Icosicosidodecahedron",
- "Small Icosacronic Hexecontahedron",
- "Icosahedral (I[2a])",
- "",
- "",
- 40, 71},
-
- /* 72 */ {"|5/2 3 3", "Small Snub Icosicosidodecahedron",
- "Small Hexagonal Hexecontahedron",
- "Icosahedral (I[2a])",
- "",
- "",
- 41, 110},
- /* (3/2 5 5) (I2b) */
-
- /* 74 */ {"3/2 5|5", "Small Dodecicosidodecahedron",
- "Small Dodecacronic Hexecontahedron",
- "Icosahedral (I[2b])",
- "",
- "",
- 42, 72},
- /* (2 5/2 5) (I3) */
-
- /* 76 */ {"5|2 5/2", "Small Stellated Dodecahedron",
- "Great Dodecahedron",
- "Icosahedral (I[3])",
- "Kepler-Poinsot Solid",
- "Kepler-Poinsot Solid",
- 43, 20},
-
- /* 78 */ {"5/2|2 5", "Great Dodecahedron",
- "Small Stellated Dodecahedron",
- "Icosahedral (I[3])",
- "Kepler-Poinsot Solid",
- "Kepler-Poinsot Solid",
- 44, 21},
-
- /* 80 */ {"2|5/2 5", "Great Dodecadodecahedron",
- "Medial Rhombic Triacontahedron",
- "Icosahedral (I[3])",
- "",
- "",
- 45, 73},
-
- /* 82 */ {"2 5/2|5", "Truncated Great Dodecahedron",
- "Small Stellapentakisdodecahedron",
- "Icosahedral (I[3])",
- "",
- "",
- 47, 75},
-
- /* 84 */ {"5/2 5|2", "Rhombidodecadodecahedron",
- "Medial Deltoidal Hexecontahedron",
- "Icosahedral (I[3])",
- "",
- "",
- 48, 76},
-
- /* 86 */ {"2 5/2 5|", "Small Rhombidodecahedron",
- "Small Rhombidodecacron",
- "Icosahedral (I[3])",
- "",
- "",
- 46, 74},
-
- /* 88 */ {"|2 5/2 5", "Snub Dodecadodecahedron",
- "Medial Pentagonal Hexecontahedron",
- "Icosahedral (I[3])",
- "",
- "",
- 49, 111},
- /* (5/3 3 5) (I4) */
-
- /* 90 */ {"3|5/3 5", "Ditrigonal Dodecadodecahedron",
- "Medial Triambic Icosahedron",
- "Icosahedral (I[4])",
- "",
- "",
- 53, 80},
-
- /* 92 */ {"3 5|5/3", "Great Ditrigonal Dodecicosidodecahedron",
- "Great Ditrigonal Dodecacronic Hexecontahedron",
- "Icosahedral (I[4])",
- "",
- "",
- 54, 81},
-
- /* 94 */ {"5/3 3|5", "Small Ditrigonal Dodecicosidodecahedron",
- "Small Ditrigonal Dodecacronic Hexecontahedron",
- "Icosahedral (I[4])",
- "",
- "",
- 55, 82},
-
- /* 96 */ {"5/3 5|3", "Icosidodecadodecahedron",
- "Medial Icosacronic Hexecontahedron",
- "Icosahedral (I[4])",
- "",
- "",
- 56, 83},
-
- /* 98 */ {"5/3 3 5|", "Icositruncated Dodecadodecahedron",
- "Tridyakisicosahedron",
- "Icosahedral (I[4])",
- "",
- "",
- 57, 84},
-
- /* 100 */ {"|5/3 3 5", "Snub Icosidodecadodecahedron",
- "Medial Hexagonal Hexecontahedron",
- "Icosahedral (I[4])",
- "",
- "",
- 58, 112},
- /* (3/2 3 5) (I6b) */
-
- /* 102 */ {"3/2|3 5", "Great Ditrigonal Icosidodecahedron",
- "Great Triambic Icosahedron",
- "Icosahedral (I[6b])",
- "",
- "",
- 61, 87},
-
- /* 104 */ {"3/2 5|3", "Great Icosicosidodecahedron",
- "Great Icosacronic Hexecontahedron",
- "Icosahedral (I[6b])",
- "",
- "",
- 62, 88},
-
- /* 106 */ {"3/2 3|5", "Small Icosihemidodecahedron",
- "Small Icosihemidodecacron",
- "Icosahedral (I[6b])",
- "",
- "",
- 63, 89},
-
- /* 108 */ {"3/2 3 5|", "Small Dodecicosahedron",
- "Small Dodecicosacron",
- "Icosahedral (I[6b])",
- "",
- "",
- 64, 90},
- /* (5/4 5 5) (I6c) */
-
- /* 110 */ {"5/4 5|5", "Small Dodecahemidodecahedron",
- "Small Dodecahemidodecacron",
- "Icosahedral (I[6c])",
- "",
- "",
- 65, 91},
- /* (2 5/2 3) (I7) */
-
- /* 112 */ {"3|2 5/2", "Great Stellated Dodecahedron",
- "Great Icosahedron",
- "Icosahedral (I[7])",
- "Kepler-Poinsot Solid",
- "Kepler-Poinsot Solid",
- 68, 22},
-
- /* 114 */ {"5/2|2 3", "Great Icosahedron",
- "Great Stellated Dodecahedron",
- "Icosahedral (I[7])",
- "Kepler-Poinsot Solid",
- "Kepler-Poinsot Solid",
- 69, 41},
-
- /* 116 */ {"2|5/2 3", "Great Icosidodecahedron",
- "Great Rhombic Triacontahedron",
- "Icosahedral (I[7])",
- "",
- "",
- 70, 94},
-
- /* 118 */ {"2 5/2|3", "Great Truncated Icosahedron",
- "Great Stellapentakisdodecahedron",
- "Icosahedral (I[7])",
- "",
- "",
- 71, 95},
-
- /* 120 */ {"2 5/2 3|", "Rhombicosahedron",
- "Rhombicosacron",
- "Icosahedral (I[7])",
- "",
- "",
- 72, 96},
-
- /* 122 */ {"|2 5/2 3", "Great Snub Icosidodecahedron",
- "Great Pentagonal Hexecontahedron",
- "Icosahedral (I[7])",
- "",
- "",
- 73, 113},
- /* (5/3 2 5) (I9) */
-
- /* 124 */ {"2 5|5/3", "Small Stellated Truncated Dodecahedron",
- "Great Pentakisdodecahedron",
- "Icosahedral (I[9])",
- "",
- "",
- 74, 97},
-
- /* 126 */ {"5/3 2 5|", "Truncated Dodecadodecahedron",
- "Medial Disdyakistriacontahedron",
- "Icosahedral (I[9])",
- "",
- "",
- 75, 98},
-
- /* 128 */ {"|5/3 2 5", "Inverted Snub Dodecadodecahedron",
- "Medial Inverted Pentagonal Hexecontahedron",
- "Icosahedral (I[9])",
- "",
- "",
- 76, 114},
- /* (5/3 5/2 3) (I10a) */
-
- /* 130 */ {"5/2 3|5/3", "Great Dodecicosidodecahedron",
- "Great Dodecacronic Hexecontahedron",
- "Icosahedral (I[10a])",
- "",
- "",
- 77, 99},
-
- /* 132 */ {"5/3 5/2|3", "Small Dodecahemicosahedron",
- "Small Dodecahemicosacron",
- "Icosahedral (I[10a])",
- "",
- "",
- 78, 100},
-
- /* 134 */ {"5/3 5/2 3|", "Great Dodecicosahedron",
- "Great Dodecicosacron",
- "Icosahedral (I[10a])",
- "",
- "",
- 79, 101},
-
- /* 136 */ {"|5/3 5/2 3", "Great Snub Dodecicosidodecahedron",
- "Great Hexagonal Hexecontahedron",
- "Icosahedral (I[10a])",
- "",
- "",
- 80, 115},
- /* (5/4 3 5) (I10b) */
-
- /* 138 */ {"5/4 5|3", "Great Dodecahemicosahedron",
- "Great Dodecahemicosacron",
- "Icosahedral (I[10b])",
- "",
- "",
- 81, 102},
- /* (5/3 2 3) (I13) */
-
- /* 140 */ {"2 3|5/3", "Great Stellated Truncated Dodecahedron",
- "Great Triakisicosahedron",
- "Icosahedral (I[13])",
- "",
- "",
- 83, 104},
-
- /* 142 */ {"5/3 3|2", "Great Rhombicosidodecahedron",
- "Great Deltoidal Hexecontahedron",
- "Icosahedral (I[13])",
- "",
- "",
- 84, 105},
-
- /* 144 */ {"5/3 2 3|", "Great Truncated Icosidodecahedron",
- "Great Disdyakistriacontahedron",
- "Icosahedral (I[13])",
- "",
- "",
- 87, 108},
-
- /* 146 */ {"|5/3 2 3", "Great Inverted Snub Icosidodecahedron",
- "Great Inverted Pentagonal Hexecontahedron",
- "Icosahedral (I[13])",
- "",
- "",
- 88, 116},
- /* (5/3 5/3 5/2) (I18a) */
-
- /* 148 */ {"5/3 5/2|5/3", "Great Dodecahemidodecahedron",
- "Great Dodecahemidodecacron",
- "Icosahedral (I[18a])",
- "",
- "",
- 86, 107},
- /* (3/2 5/3 3) (I18b) */
-
- /* 150 */ {"3/2 3|5/3", "Great Icosihemidodecahedron",
- "Great Icosihemidodecacron",
- "Icosahedral (I[18b])",
- "",
- "",
- 85, 106},
- /* (3/2 3/2 5/3) (I22) */
-
- /* 152 */ {"|3/2 3/2 5/2","Small Retrosnub Icosicosidodecahedron",
- "Small Hexagrammic Hexecontahedron",
- "Icosahedral (I[22])",
- "",
- "",
- 91, 118},
- /* (3/2 5/3 2) (I23) */
-
- /* 154 */ {"3/2 5/3 2|", "Great Rhombidodecahedron",
- "Great Rhombidodecacron",
- "Icosahedral (I[23])",
- "",
- "",
- 89, 109},
-
- /* 156 */ {"|3/2 5/3 2", "Great Retrosnub Icosidodecahedron",
- "Great Pentagrammic Hexecontahedron",
- "Icosahedral (I[23])",
- "",
- "",
- 90, 117},
-
- /****************************************************************************
- * Last But Not Least
- ***************************************************************************/
-
- /* 158 */ {"3/2 5/3 3 5/2", "Great Dirhombicosidodecahedron",
- "Great Dirhombicosidodecacron",
- "Non-Wythoffian",
- "",
- "",
- 92, 119}
-};
-
-static int last_uniform = sizeof (uniform) / sizeof (uniform[0]);
-
-
-
-static int unpacksym(const char *sym, Polyhedron *P);
-static int moebius(Polyhedron *P);
-static int decompose(Polyhedron *P);
-static int guessname(Polyhedron *P);
-static int newton(Polyhedron *P, int need_approx);
-static int exceptions(Polyhedron *P);
-static int count(Polyhedron *P);
-static int configuration(Polyhedron *P);
-static int vertices(Polyhedron *P);
-static int faces(Polyhedron *P);
-static int edgelist(Polyhedron *P);
-
-static Polyhedron *
-kaleido(const char *sym,
- int need_coordinates, int need_edgelist, int need_approx,
- int just_list)
-{
- Polyhedron *P;
- /*
- * Allocate a Polyhedron structure P.
- */
- if (!(P = polyalloc()))
- return 0;
- /*
- * Unpack input symbol into P.
- */
- if (!unpacksym(sym, P))
- return 0;
- /*
- * Find Mebius triangle, its density and Euler characteristic.
- */
- if (!moebius(P))
- return 0;
- /*
- * Decompose Schwarz triangle.
- */
- if (!decompose(P))
- return 0;
- /*
- * Find the names of the polyhedron and its dual.
- */
- if (!guessname(P))
- return 0;
- if (just_list)
- return P;
- /*
- * Solve Fundamental triangles, optionally printing approximations.
- */
- if (!newton(P,need_approx))
- return 0;
- /*
- * Deal with exceptional polyhedra.
- */
- if (!exceptions(P))
- return 0;
- /*
- * Count edges and faces, update density and characteristic if needed.
- */
- if (!count(P))
- return 0;
- /*
- * Generate printable vertex configuration.
- */
- if (!configuration(P))
- return 0;
- /*
- * Compute coordinates.
- */
- if (!need_coordinates && !need_edgelist)
- return P;
- if (!vertices(P))
- return 0;
- if (!faces (P))
- return 0;
- /*
- * Compute edgelist.
- */
- if (!need_edgelist)
- return P;
- if (!edgelist(P))
- return 0;
- return P;
-}
-
-/*
- * Allocate a blank Polyhedron structure and initialize some of its nonblank
- * fields.
- *
- * Array and matrix field are allocated when needed.
- */
-static Polyhedron *
-polyalloc()
-{
- Polyhedron *P;
- Calloc(P, 1, Polyhedron);
- P->index = -1;
- P->even = -1;
- P->K = 2;
- return P;
-}
-
-/*
- * Free the struture allocated by polyalloc(), as well as all the array and
- * matrix fields.
- */
-static void
-polyfree(Polyhedron *P)
-{
- Free(P->Fi);
- Free(P->n);
- Free(P->m);
- Free(P->gamma);
- Free(P->rot);
- Free(P->snub);
- Free(P->firstrot);
- Free(P->anti);
- Free(P->ftype);
- Free(P->polyform);
- Free(P->config);
- if (P->index < 0) {
- Free(P->name);
- Free(P->dual_name);
- }
- Free(P->v);
- Free(P->f);
- Matfree(P->e, 2);
- Matfree(P->dual_e, 2);
- Matfree(P->incid, P->M);
- Matfree(P->adj, P->M);
- free(P);
-}
-
-static void *
-matalloc(int rows, int row_size)
-{
- void **mat;
- int i = 0;
- if (!(mat = malloc(rows * sizeof (void *))))
- return 0;
- while ((mat[i] = malloc(row_size)) && ++i < rows)
- ;
- if (i == rows)
- return (void *)mat;
- while (--i >= 0)
- free(mat[i]);
- free(mat);
- return 0;
-}
-
-static void
-matfree(void *mat, int rows)
-{
- while (--rows >= 0)
- free(((void **)mat)[rows]);
- free(mat);
-}
-
-/*
- * compute the mathematical modulus function.
- */
-static int
-mod (int i, int j)
-{
- return (i%=j)>=0?i:j<0?i-j:i+j;
-}
-
-
-/*
- * Find the numerator and the denominator using the Euclidean algorithm.
- */
-static void
-frac(double x)
-{
- static const Fraction zero = {0,1}, inf = {1,0};
- Fraction r0, r;
- long f;
- double s = x;
- r = zero;
- frax = inf;
- for (;;) {
- if (fabs(s) > (double) MAXLONG)
- return;
- f = (long) floor (s);
- r0 = r;
- r = frax;
- frax.n = frax.n * f + r0.n;
- frax.d = frax.d * f + r0.d;
- if (x == (double)frax.n/(double)frax.d)
- return;
- s = 1 / (s - f);
- }
-}
-
-
-/*
- * Unpack input symbol: Wythoff symbol or an index to uniform[]. The symbol is
- * a # followed by a number, or a three fractions and a bar in some order. We
- * allow no bars only if it result from the input symbol #80.
- */
-static int
-unpacksym(const char *sym, Polyhedron *P)
-{
- int i = 0, n, d, bars = 0;
- char c;
- while ((c = *sym++) && isspace(c))
- ;
- if (!c) Err("no data");
- if (c == '#') {
- while ((c = *sym++) && isspace(c))
- ;
- if (!c)
- Err("no digit after #");
- if (!isdigit(c))
- Err("not a digit");
- n = c - '0';
- while ((c = *sym++) && isdigit(c))
- n = n * 10 + c - '0';
- if (!n)
- Err("zero index");
- if (n > last_uniform)
- Err("index too big");
- sym--;
- while ((c = *sym++) && isspace(c))
- ;
- if (c)
- Err("data exceeded");
- sym = uniform[P->index = n - 1].Wythoff;
- } else
- sym--;
-
- for (;;) {
- while ((c = *sym++) && isspace(c))
- ;
- if (!c) {
- if (i == 4 && (bars || P->index == last_uniform - 1))
- return 1;
- if (!bars)
- Err("no bars");
- Err("not enough fractions");
- }
- if (i == 4)
- Err("data exceeded");
- if (c == '|'){
- if (++bars > 1)
- Err("too many bars");
- P->p[i++] = 0;
- continue;
- }
- if (!isdigit(c))
- Err("not a digit");
- n = c - '0';
- while ((c = *sym++) && isdigit(c))
- n = n * 10 + c - '0';
- if (c && isspace (c))
- while ((c = *sym++) && isspace(c))
- ;
- if (c != '/') {
- sym--;
- if ((P->p[i++] = n) <= 1)
- Err("fraction<=1");
- continue;
- }
- while ((c = *sym++) && isspace(c))
- ;
- if (!c || !isdigit(c))
- return 0;
- d = c - '0';
- while ((c = *sym++) && isdigit(c))
- d = d * 10 + c - '0';
- if (!d)
- Err("zero denominator");
- sym--;
- if ((P->p[i++] = (double) n / d) <= 1)
- Err("fraction<=1");
- }
-}
-
-/*
- * Using Wythoff symbol (p|qr, pq|r, pqr| or |pqr), find the Moebius triangle
- * (2 3 K) (or (2 2 n)) of the Schwarz triangle (pqr), the order g of its
- * symmetry group, its Euler characteristic chi, and its covering density D.
- * g is the number of copies of (2 3 K) covering the sphere, i.e.,
- *
- * g * pi * (1/2 + 1/3 + 1/K - 1) = 4 * pi
- *
- * D is the number of times g copies of (pqr) cover the sphere, i.e.
- *
- * D * 4 * pi = g * pi * (1/p + 1/q + 1/r - 1)
- *
- * chi is V - E + F, where F = g is the number of triangles, E = 3*g/2 is the
- * number of triangle edges, and V = Vp+ Vq+ Vr, with Vp = g/(2*np) being the
- * number of vertices with angle pi/p (np is the numerator of p).
- */
-static int
-moebius(Polyhedron *P)
-{
- int twos = 0, j, len = 1;
- /*
- * Arrange Wythoff symbol in a presentable form. In the same time check the
- * restrictions on the three fractions: They all have to be greater then one,
- * and the numerators 4 or 5 cannot occur together. We count the ocurrences
- * of 2 in `two', and save the largest numerator in `P->K', since they
- * reflect on the symmetry group.
- */
- P->K = 2;
- if (P->index == last_uniform - 1) {
- Malloc(P->polyform, ++len, char);
- strcpy(P->polyform, "|");
- } else
- Calloc(P->polyform, len, char);
- for (j = 0; j < 4; j++) {
- if (P->p[j]) {
- char *s;
- Sprintfrac(s, P->p[j]);
- if (j && P->p[j-1]) {
- Realloc(P->polyform, len += strlen (s) + 1, char);
- strcat(P->polyform, " ");
- } else
- Realloc (P->polyform, len += strlen (s), char);
- strcat(P->polyform, s);
- free(s);
- if (P->p[j] != 2) {
- int k;
- if ((k = numerator (P->p[j])) > P->K) {
- if (P->K == 4)
- break;
- P->K = k;
- } else if (k < P->K && k == 4)
- break;
- } else
- twos++;
- } else {
- Realloc(P->polyform, ++len, char);
- strcat(P->polyform, "|");
- }
- }
- /*
- * Find the symmetry group P->K (where 2, 3, 4, 5 represent the dihedral,
- * tetrahedral, octahedral and icosahedral groups, respectively), and its
- * order P->g.
- */
- if (twos >= 2) {/* dihedral */
- P->g = 4 * P->K;
- P->K = 2;
- } else {
- if (P->K > 5)
- Err("numerator too large");
- P->g = 24 * P->K / (6 - P->K);
- }
- /*
- * Compute the nominal density P->D and Euler characteristic P->chi.
- * In few exceptional cases, these values will be modified later.
- */
- if (P->index != last_uniform - 1) {
- int i;
- P->D = P->chi = - P->g;
- for (j = 0; j < 4; j++) if (P->p[j]) {
- P->chi += i = P->g / numerator(P->p[j]);
- P->D += i * denominator(P->p[j]);
- }
- P->chi /= 2;
- P->D /= 4;
- if (P->D <= 0)
- Err("nonpositive density");
- }
- return 1;
-}
-
-/*
- * Decompose Schwarz triangle into N right triangles and compute the vertex
- * count V and the vertex valency M. V is computed from the number g of
- * Schwarz triangles in the cover, divided by the number of triangles which
- * share a vertex. It is halved for one-sided polyhedra, because the
- * kaleidoscopic construction really produces a double orientable covering of
- * such polyhedra. All q' q|r are of the "hemi" type, i.e. have equatorial {2r}
- * faces, and therefore are (except 3/2 3|3 and the dihedra 2 2|r) one-sided. A
- * well known example is 3/2 3|4, the "one-sided heptahedron". Also, all p q r|
- * with one even denominator have a crossed parallelogram as a vertex figure,
- * and thus are one-sided as well.
- */
-static int
-decompose(Polyhedron *P)
-{
- int j, J, *s, *t;
- if (!P->p[1]) { /* p|q r */
- P->N = 2;
- P->M = 2 * numerator(P->p[0]);
- P->V = P->g / P->M;
- Malloc(P->n, P->N, double);
- Malloc(P->m, P->N, double);
- Malloc(P->rot, P->M, int);
- s = P->rot;
- for (j = 0; j < 2; j++) {
- P->n[j] = P->p[j+2];
- P->m[j] = P->p[0];
- }
- for (j = P->M / 2; j--;) {
- *s++ = 0;
- *s++ = 1;
- }
- } else if (!P->p[2]) { /* p q|r */
- P->N = 3;
- P->M = 4;
- P->V = P->g / 2;
- Malloc(P->n, P->N, double);
- Malloc(P->m, P->N, double);
- Malloc(P->rot, P->M, int);
- s = P->rot;
- P->n[0] = 2 * P->p[3];
- P->m[0] = 2;
- for (j = 1; j < 3; j++) {
- P->n[j] = P->p[j-1];
- P->m[j] = 1;
- *s++ = 0;
- *s++ = j;
- }
- if (fabs(P->p[0] - compl (P->p[1])) < DBL_EPSILON) {/* p = q' */
- /* P->p[0]==compl(P->p[1]) should work. However, MSDOS
- * yeilds a 7e-17 difference! Reported by Jim Buddenhagen
- * <jb1556@daditz.sbc.com> */
- P->hemi = 1;
- P->D = 0;
- if (P->p[0] != 2 && !(P->p[3] == 3 && (P->p[0] == 3 ||
- P->p[1] == 3))) {
- P->onesided = 1;
- P->V /= 2;
- P->chi /= 2;
- }
- }
- } else if (!P->p[3]) { /* p q r| */
- P->M = P->N = 3;
- P->V = P->g;
- Malloc(P->n, P->N, double);
- Malloc(P->m, P->N, double);
- Malloc(P->rot, P->M, int);
- s = P->rot;
- for (j = 0; j < 3; j++) {
- if (!(denominator(P->p[j]) % 2)) {
- /* what happens if there is more then one even denominator? */
- if (P->p[(j+1)%3] != P->p[(j+2)%3]) { /* needs postprocessing */
- P->even = j;/* memorize the removed face */
- P->chi -= P->g / numerator(P->p[j]) / 2;
- P->onesided = 1;
- P->D = 0;
- } else {/* for p = q we get a double 2 2r|p */
- /* noted by Roman Maeder <maeder@inf.ethz.ch> for 4 4 3/2| */
- /* Euler characteristic is still wrong */
- P->D /= 2;
- }
- P->V /= 2;
- }
- P->n[j] = 2 * P->p[j];
- P->m[j] = 1;
- *s++ = j;
- }
- } else { /* |p q r - snub polyhedron */
- P->N = 4;
- P->M = 6;
- P->V = P->g / 2;/* Only "white" triangles carry a vertex */
- Malloc(P->n, P->N, double);
- Malloc(P->m, P->N, double);
- Malloc(P->rot, P->M, int);
- Malloc(P->snub, P->M, int);
- s = P->rot;
- t = P->snub;
- P->m[0] = P->n[0] = 3;
- for (j = 1; j < 4; j++) {
- P->n[j] = P->p[j];
- P->m[j] = 1;
- *s++ = 0;
- *s++ = j;
- *t++ = 1;
- *t++ = 0;
- }
- }
- /*
- * Sort the fundamental triangles (using bubble sort) according to decreasing
- * n[i], while pushing the trivial triangles (n[i] = 2) to the end.
- */
- J = P->N - 1;
- while (J) {
- int last;
- last = J;
- J = 0;
- for (j = 0; j < last; j++) {
- if ((P->n[j] < P->n[j+1] || P->n[j] == 2) && P->n[j+1] != 2) {
- int i;
- double temp;
- temp = P->n[j];
- P->n[j] = P->n[j+1];
- P->n[j+1] = temp;
- temp = P->m[j];
- P->m[j] = P->m[j+1];
- P->m[j+1] = temp;
- for (i = 0; i < P->M; i++) {
- if (P->rot[i] == j)
- P->rot[i] = j+1;
- else if (P->rot[i] == j+1)
- P->rot[i] = j;
- }
- if (P->even != -1) {
- if (P->even == j)
- P->even = j+1;
- else if (P->even == j+1)
- P->even = j;
- }
- J = j;
- }
- }
- }
- /*
- * Get rid of repeated triangles.
- */
- for (J = 0; J < P->N && P->n[J] != 2;J++) {
- int k, i;
- for (j = J+1; j < P->N && P->n[j]==P->n[J]; j++)
- P->m[J] += P->m[j];
- k = j - J - 1;
- if (k) {
- for (i = j; i < P->N; i++) {
- P->n[i - k] = P->n[i];
- P->m[i - k] = P->m[i];
- }
- P->N -= k;
- for (i = 0; i < P->M; i++) {
- if (P->rot[i] >= j)
- P->rot[i] -= k;
- else if (P->rot[i] > J)
- P->rot[i] = J;
- }
- if (P->even >= j)
- P->even -= k;
- }
- }
- /*
- * Get rid of trivial triangles.
- */
- if (!J)
- J = 1; /* hosohedron */
- if (J < P->N) {
- int i;
- P->N = J;
- for (i = 0; i < P->M; i++) {
- if (P->rot[i] >= P->N) {
- for (j = i + 1; j < P->M; j++) {
- P->rot[j-1] = P->rot[j];
- if (P->snub)
- P->snub[j-1] = P->snub[j];
- }
- P->M--;
- }
- }
- }
- /*
- * Truncate arrays
- */
- Realloc(P->n, P->N, double);
- Realloc(P->m, P->N, double);
- Realloc(P->rot, P->M, int);
- if (P->snub)
- Realloc(P->snub, P->M, int);
- return 1;
-}
-
-
-static int dihedral(Polyhedron *P, const char *name, const char *dual_name);
-
-
-/*
- * Get the polyhedron name, using standard list or guesswork. Ideally, we
- * should try to locate the Wythoff symbol in the standard list (unless, of
- * course, it is dihedral), after doing few normalizations, such as sorting
- * angles and splitting isoceles triangles.
- */
-static int
-guessname(Polyhedron *P)
-{
- if (P->index != -1) {/* tabulated */
- P->name = uniform[P->index].name;
- P->dual_name = uniform[P->index].dual;
- P->group = uniform[P->index].group;
- P->class = uniform[P->index].class;
- P->dual_class = uniform[P->index].dual_class;
- return 1;
- } else if (P->K == 2) {/* dihedral nontabulated */
- if (!P->p[0]) {
- if (P->N == 1) {
- Malloc(P->name, sizeof ("Octahedron"), char);
- Malloc(P->dual_name, sizeof ("Cube"), char);
- strcpy(P->name, "Octahedron");
- strcpy(P->dual_name, "Cube");
- return 1;
- }
- P->gon = P->n[0] == 3 ? P->n[1] : P->n[0];
- if (P->gon >= 2)
- return dihedral(P, "Antiprism", "Deltohedron");
- else
- return dihedral(P, "Crossed Antiprism", "Concave Deltohedron");
- } else if (!P->p[3] ||
- (!P->p[2] &&
- P->p[3] == 2)) {
- if (P->N == 1) {
- Malloc(P->name, sizeof("Cube"), char);
- Malloc(P->dual_name, sizeof("Octahedron"), char);
- strcpy(P->name, "Cube");
- strcpy(P->dual_name, "Octahedron");
- return 1;
- }
- P->gon = P->n[0] == 4 ? P->n[1] : P->n[0];
- return dihedral(P, "Prism", "Dipyramid");
- } else if (!P->p[1] && P->p[0] != 2) {
- P->gon = P->m[0];
- return dihedral(P, "Hosohedron", "Dihedron");
- } else {
- P->gon = P->n[0];
- return dihedral(P, "Dihedron", "Hosohedron");
- }
- } else {/* other nontabulated */
- static const char *pre[] = {"Tetr", "Oct", "Icos"};
- Malloc(P->name, 50, char);
- Malloc(P->dual_name, 50, char);
- sprintf(P->name, "%sahedral ", pre[P->K - 3]);
- if (P->onesided)
- strcat (P->name, "One-Sided ");
- else if (P->D == 1)
- strcat(P->name, "Convex ");
- else
- strcat(P->name, "Nonconvex ");
- strcpy(P->dual_name, P->name);
- strcat(P->name, "Isogonal Polyhedron");
- strcat(P->dual_name, "Isohedral Polyhedron");
- Realloc(P->name, strlen (P->name) + 1, char);
- Realloc(P->dual_name, strlen (P->dual_name) + 1, char);
- return 1;
- }
-}
-
-static int
-dihedral(Polyhedron *P, const char *name, const char *dual_name)
-{
- char *s;
- int i;
- Sprintfrac(s, P->gon < 2 ? compl (P->gon) : P->gon);
- i = strlen(s) + sizeof ("-gonal ");
- Malloc(P->name, i + strlen (name), char);
- Malloc(P->dual_name, i + strlen (dual_name), char);
- sprintf(P->name, "%s-gonal %s", s, name);
- sprintf(P->dual_name, "%s-gonal %s", s, dual_name);
- free(s);
- return 1;
-}
-
-/*
- * Solve the fundamental right spherical triangles.
- * If need_approx is set, print iterations on standard error.
- */
-static int
-newton(Polyhedron *P, int need_approx)
-{
- /*
- * First, we find initial approximations.
- */
- int j;
- double cosa;
- Malloc(P->gamma, P->N, double);
- if (P->N == 1) {
- P->gamma[0] = M_PI / P->m[0];
- return 1;
- }
- for (j = 0; j < P->N; j++)
- P->gamma[j] = M_PI / 2 - M_PI / P->n[j];
- errno = 0; /* may be non-zero from some reason */
- /*
- * Next, iteratively find closer approximations for gamma[0] and compute
- * other gamma[j]'s from Napier's equations.
- */
- if (need_approx)
- fprintf(stderr, "Solving %s\n", P->polyform);
- for (;;) {
- double delta = M_PI, sigma = 0;
- for (j = 0; j < P->N; j++) {
- if (need_approx)
- fprintf(stderr, "%-20.15f", P->gamma[j]);
- delta -= P->m[j] * P->gamma[j];
- }
- if (need_approx)
- printf("(%g)\n", delta);
- if (fabs(delta) < 11 * DBL_EPSILON)
- return 1;
- /* On a RS/6000, fabs(delta)/DBL_EPSILON may occilate between 8 and
- * 10. Reported by David W. Sanderson <dws@ssec.wisc.edu> */
- for (j = 0; j < P->N; j++)
- sigma += P->m[j] * tan(P->gamma[j]);
- P->gamma[0] += delta * tan(P->gamma[0]) / sigma;
- if (P->gamma[0] < 0 || P->gamma[0] > M_PI)
- Err("gamma out of bounds");
- cosa = cos(M_PI / P->n[0]) / sin(P->gamma[0]);
- for (j = 1; j < P->N; j++)
- P->gamma[j] = asin(cos(M_PI / P->n[j]) / cosa);
- if (errno)
- Err(strerror(errno));
- }
-}
-
-/*
- * Postprocess pqr| where r has an even denominator (cf. Coxeter &al. Sec.9).
- * Remove the {2r} and add a retrograde {2p} and retrograde {2q}.
- */
-static int
-exceptions(Polyhedron *P)
-{
- int j;
- if (P->even != -1) {
- P->M = P->N = 4;
- Realloc(P->n, P->N, double);
- Realloc(P->m, P->N, double);
- Realloc(P->gamma, P->N, double);
- Realloc(P->rot, P->M, int);
- for (j = P->even + 1; j < 3; j++) {
- P->n[j-1] = P->n[j];
- P->gamma[j-1] = P->gamma[j];
- }
- P->n[2] = compl(P->n[1]);
- P->gamma[2] = - P->gamma[1];
- P->n[3] = compl(P->n[0]);
- P->m[3] = 1;
- P->gamma[3] = - P->gamma[0];
- P->rot[0] = 0;
- P->rot[1] = 1;
- P->rot[2] = 3;
- P->rot[3] = 2;
- }
-
- /*
- * Postprocess the last polyhedron |3/2 5/3 3 5/2 by taking a |5/3 3 5/2,
- * replacing the three snub triangles by four equatorial squares and adding
- * the missing {3/2} (retrograde triangle, cf. Coxeter &al. Sec. 11).
- */
- if (P->index == last_uniform - 1) {
- P->N = 5;
- P->M = 8;
- Realloc(P->n, P->N, double);
- Realloc(P->m, P->N, double);
- Realloc(P->gamma, P->N, double);
- Realloc(P->rot, P->M, int);
- Realloc(P->snub, P->M, int);
- P->hemi = 1;
- P->D = 0;
- for (j = 3; j; j--) {
- P->m[j] = 1;
- P->n[j] = P->n[j-1];
- P->gamma[j] = P->gamma[j-1];
- }
- P->m[0] = P->n[0] = 4;
- P->gamma[0] = M_PI / 2;
- P->m[4] = 1;
- P->n[4] = compl(P->n[1]);
- P->gamma[4] = - P->gamma[1];
- for (j = 1; j < 6; j += 2) P->rot[j]++;
- P->rot[6] = 0;
- P->rot[7] = 4;
- P->snub[6] = 1;
- P->snub[7] = 0;
- }
- return 1;
-}
-
-/*
- * Compute edge and face counts, and update D and chi. Update D in the few
- * cases the density of the polyhedron is meaningful but different than the
- * density of the corresponding Schwarz triangle (cf. Coxeter &al., p. 418 and
- * p. 425).
- * In these cases, spherical faces of one type are concave (bigger than a
- * hemisphere), and the actual density is the number of these faces less the
- * computed density. Note that if j != 0, the assignment gamma[j] = asin(...)
- * implies gamma[j] cannot be obtuse. Also, compute chi for the only
- * non-Wythoffian polyhedron.
- */
-static int
-count(Polyhedron *P)
-{
- int j, temp;
- Malloc(P->Fi, P->N, int);
- for (j = 0; j < P->N; j++) {
- P->E += temp = P->V * numerator(P->m[j]);
- P->F += P->Fi[j] = temp / numerator(P->n[j]);
- }
- P->E /= 2;
- if (P->D && P->gamma[0] > M_PI / 2)
- P->D = P->Fi[0] - P->D;
- if (P->index == last_uniform - 1)
- P->chi = P->V - P->E + P->F;
- return 1;
-}
-
-/*
- * Generate a printable vertex configuration symbol.
- */
-static int
-configuration(Polyhedron *P)
-{
- int j, len = 2;
- for (j = 0; j < P->M; j++) {
- char *s;
- Sprintfrac(s, P->n[P->rot[j]]);
- len += strlen (s) + 2;
- if (!j) {
- Malloc(P->config, len, char);
-/* strcpy(P->config, "(");*/
- strcpy(P->config, "");
- } else {
- Realloc(P->config, len, char);
- strcat(P->config, ", ");
- }
- strcat(P->config, s);
- free(s);
- }
-/* strcat (P->config, ")");*/
- if ((j = denominator (P->m[0])) != 1) {
- char s[MAXDIGITS + 2];
- sprintf(s, "/%d", j);
- Realloc(P->config, len + strlen (s), char);
- strcat(P->config, s);
- }
- return 1;
-}
-
-/*
- * Compute polyhedron vertices and vertex adjecency lists.
- * The vertices adjacent to v[i] are v[adj[0][i], v[adj[1][i], ...
- * v[adj[M-1][i], ordered counterclockwise. The algorith is a BFS on the
- * vertices, in such a way that the vetices adjacent to a givem vertex are
- * obtained from its BFS parent by a cyclic sequence of rotations. firstrot[i]
- * points to the first rotaion in the sequence when applied to v[i]. Note that
- * for non-snub polyhedra, the rotations at a child are opposite in sense when
- * compared to the rotations at the parent. Thus, we fill adj[*][i] from the
- * end to signify clockwise rotations. The firstrot[] array is not needed for
- * display thus it is freed after being used for face computations below.
- */
-static int
-vertices(Polyhedron *P)
-{
- int i, newV = 2;
- double cosa;
- Malloc(P->v, P->V, Vector);
- Matalloc(P->adj, P->M, P->V, int);
- Malloc(P->firstrot, P->V, int); /* temporary , put in Polyhedron
- structure so that may be freed on
- error */
- cosa = cos(M_PI / P->n[0]) / sin(P->gamma[0]);
- P->v[0].x = 0;
- P->v[0].y = 0;
- P->v[0].z = 1;
- P->firstrot[0] = 0;
- P->adj[0][0] = 1;
- P->v[1].x = 2 * cosa * sqrt(1 - cosa * cosa);
- P->v[1].y = 0;
- P->v[1].z = 2 * cosa * cosa - 1;
- if (!P->snub) {
- P->firstrot[1] = 0;
- P->adj[0][1] = -1;/* start the other side */
- P->adj[P->M-1][1] = 0;
- } else {
- P->firstrot[1] = P->snub[P->M-1] ? 0 : P->M-1 ;
- P->adj[0][1] = 0;
- }
- for (i = 0; i < newV; i++) {
- int j, k;
- int last, one, start, limit;
- if (P->adj[0][i] == -1) {
- one = -1; start = P->M-2; limit = -1;
- } else {
- one = 1; start = 1; limit = P->M;
- }
- k = P->firstrot[i];
- for (j = start; j != limit; j += one) {
- Vector temp;
- int J;
- temp = rotate (P->v[P->adj[j-one][i]], P->v[i],
- one * 2 * P->gamma[P->rot[k]]);
- for (J=0; J<newV && !same(P->v[J],temp,BIG_EPSILON); J++)
- ;/* noop */
- P->adj[j][i] = J;
- last = k;
- if (++k == P->M)
- k = 0;
- if (J == newV) { /* new vertex */
- if (newV == P->V) Err ("too many vertices");
- P->v[newV++] = temp;
- if (!P->snub) {
- P->firstrot[J] = k;
- if (one > 0) {
- P->adj[0][J] = -1;
- P->adj[P->M-1][J] = i;
- } else {
- P->adj[0][J] = i;
- }
- } else {
- P->firstrot[J] = !P->snub[last] ? last :
- !P->snub[k] ? (k+1)%P->M : k ;
- P->adj[0][J] = i;
- }
- }
- }
- }
- return 1;
-}
-
-/*
- * Compute polyhedron faces (dual vertices) and incidence matrices.
- * For orientable polyhedra, we can distinguish between the two faces meeting
- * at a given directed edge and identify the face on the left and the face on
- * the right, as seen from the outside. For one-sided polyhedra, the vertex
- * figure is a papillon (in Coxeter &al. terminology, a crossed parallelogram)
- * and the two faces meeting at an edge can be identified as the side face
- * (n[1] or n[2]) and the diagonal face (n[0] or n[3]).
- */
-static int
-faces(Polyhedron *P)
-{
- int i, newF = 0;
- Malloc (P->f, P->F, Vector);
- Malloc (P->ftype, P->F, int);
- Matalloc (P->incid, P->M, P->V, int);
- P->minr = 1 / fabs (tan (M_PI / P->n[P->hemi]) * tan (P->gamma[P->hemi]));
- for (i = P->M; --i>=0;) {
- int j;
- for (j = P->V; --j>=0;)
- P->incid[i][j] = -1;
- }
- for (i = 0; i < P->V; i++) {
- int j;
- for (j = 0; j < P->M; j++) {
- int i0, J;
- int pap=0;/* papillon edge type */
- if (P->incid[j][i] != -1)
- continue;
- P->incid[j][i] = newF;
- if (newF == P->F)
- Err("too many faces");
- P->f[newF] = pole(P->minr, P->v[i], P->v[P->adj[j][i]],
- P->v[P->adj[mod(j + 1, P->M)][i]]);
- P->ftype[newF] = P->rot[mod(P->firstrot[i] + ((P->adj[0][i] <
- P->adj[P->M - 1][i])
- ? j
- : -j - 2),
- P->M)];
- if (P->onesided)
- pap = (P->firstrot[i] + j) % 2;
- i0 = i;
- J = j;
- for (;;) {
- int k;
- k = i0;
- if ((i0 = P->adj[J][k]) == i) break;
- for (J = 0; J < P->M && P->adj[J][i0] != k; J++)
- ;/* noop */
- if (J == P->M)
- Err("too many faces");
- if (P->onesided && (J + P->firstrot[i0]) % 2 == pap) {
- P->incid [J][i0] = newF;
- if (++J >= P->M)
- J = 0;
- } else {
- if (--J < 0)
- J = P->M - 1;
- P->incid [J][i0] = newF;
- }
- }
- newF++;
- }
- }
- Free(P->firstrot);
- Free(P->rot);
- Free(P->snub);
- return 1;
-}
-
-/*
- * Compute edge list and graph polyhedron and dual.
- * If the polyhedron is of the "hemi" type, each edge has one finite vertex and
- * one ideal vertex. We make sure the latter is always the out-vertex, so that
- * the edge becomes a ray (half-line). Each ideal vertex is represented by a
- * unit Vector, and the direction of the ray is either parallel or
- * anti-parallel this Vector. We flag this in the array P->anti[E].
- */
-static int
-edgelist(Polyhedron *P)
-{
- int i, j, *s, *t, *u;
- Matalloc(P->e, 2, P->E, int);
- Matalloc(P->dual_e, 2, P->E, int);
- s = P->e[0];
- t = P->e[1];
- for (i = 0; i < P->V; i++)
- for (j = 0; j < P->M; j++)
- if (i < P->adj[j][i]) {
- *s++ = i;
- *t++ = P->adj[j][i];
- }
- s = P->dual_e[0];
- t = P->dual_e[1];
- if (!P->hemi)
- P->anti = 0;
- else
- Malloc(P->anti, P->E, int);
- u = P->anti;
- for (i = 0; i < P->V; i++)
- for (j = 0; j < P->M; j++)
- if (i < P->adj[j][i])
- {
- if (!u) {
- *s++ = P->incid[mod(j-1,P->M)][i];
- *t++ = P->incid[j][i];
- } else {
- if (P->ftype[P->incid[j][i]]) {
- *s = P->incid[j][i];
- *t = P->incid[mod(j-1,P->M)][i];
- } else {
- *s = P->incid[mod(j-1,P->M)][i];
- *t = P->incid[j][i];
- }
- *u++ = dot(P->f[*s++], P->f[*t++]) > 0;
- }
- }
- return 1;
-}
-
-
-static char *
-sprintfrac(double x)
-{
- char *s;
- frac (x);
- if (!frax.d) {
- Malloc(s, sizeof ("infinity"), char);
- strcpy(s, "infinity");
- } else if (frax.d == 1) {
- char n[MAXDIGITS + 1];
- sprintf(n, "%ld", frax.n);
- Malloc(s, strlen (n) + 1, char);
- strcpy(s, n);
- } else {
- char n[MAXDIGITS + 1], d[MAXDIGITS + 1];
- sprintf(n, "%ld", frax.n);
- sprintf(d, "%ld", frax.d);
- Malloc(s, strlen (n) + strlen (d) + 2, char);
- sprintf(s, "%s/%s", n, d);
- }
- return s;
-}
-
-static double
-dot(Vector a, Vector b)
-{
- return a.x * b.x + a.y * b.y + a.z * b.z;
-}
-
-static Vector
-scale(double k, Vector a)
-{
- a.x *= k;
- a.y *= k;
- a.z *= k;
- return a;
-}
-
-static Vector
-diff(Vector a, Vector b)
-{
- a.x -= b.x;
- a.y -= b.y;
- a.z -= b.z;
- return a;
-}
-
-static Vector
-cross(Vector a, Vector b)
-{
- Vector p;
- p.x = a.y * b.z - a.z * b.y;
- p.y = a.z * b.x - a.x * b.z;
- p.z = a.x * b.y - a.y * b.x;
- return p;
-}
-
-static Vector
-sum(Vector a, Vector b)
-{
- a.x += b.x;
- a.y += b.y;
- a.z += b.z;
- return a;
-}
-
-static Vector
-sum3(Vector a, Vector b, Vector c)
-{
- a.x += b.x + c.x;
- a.y += b.y + c.y;
- a.z += b.z + c.z;
- return a;
-}
-
-static Vector
-rotate(Vector vertex, Vector axis, double angle)
-{
- Vector p;
- p = scale(dot (axis, vertex), axis);
- return sum3(p, scale(cos(angle), diff(vertex, p)),
- scale(sin(angle), cross(axis, vertex)));
-}
-
-static Vector x, y, z;
-
-/*
- * rotate the standard frame
- */
-static void
-rotframe(double azimuth, double elevation, double angle)
-{
- static const Vector X = {1,0,0}, Y = {0,1,0}, Z = {0,0,1};
- Vector axis;
-
- axis = rotate(rotate (X, Y, elevation), Z, azimuth);
- x = rotate(X, axis, angle);
- y = rotate(Y, axis, angle);
- z = rotate(Z, axis, angle);
-}
-
-/*
- * rotate an array of n Vectors
- */
-static void
-rotarray(Vector *new, Vector *old, int n)
-{
- while (n--) {
- *new++ = sum3(scale(old->x, x), scale(old->y, y), scale(old->z, z));
- old++;
- }
-}
-
-static int
-same(Vector a, Vector b, double epsilon)
-{
- return fabs(a.x - b.x) < epsilon && fabs(a.y - b.y) < epsilon
- && fabs(a.z - b.z) < epsilon;
-}
-
-/*
- * Compute the polar reciprocal of the plane containing a, b and c:
- *
- * If this plane does not contain the origin, return p such that
- * dot(p,a) = dot(p,b) = dot(p,b) = r.
- *
- * Otherwise, return p such that
- * dot(p,a) = dot(p,b) = dot(p,c) = 0
- * and
- * dot(p,p) = 1.
- */
-static Vector
-pole(double r, Vector a, Vector b, Vector c)
-{
- Vector p;
- double k;
- p = cross(diff(b, a), diff(c, a));
- k = dot(p, a);
- if (fabs(k) < 1e-6)
- return scale(1 / sqrt(dot(p, p)), p);
- else
- return scale(r/ k , p);
-}
-
-
-/* output */
-
-
-
-
-static void rotframe(double azimuth, double elevation, double angle);
-static void rotarray(Vector *new, Vector *old, int n);
-static int mod (int i, int j);
-
-
-static void
-push_point (polyhedron *p, Vector v)
-{
- p->points[p->npoints].x = v.x;
- p->points[p->npoints].y = v.y;
- p->points[p->npoints].z = v.z;
- p->npoints++;
-}
-
-static void
-push_face3 (polyhedron *p, int x, int y, int z)
-{
- p->faces[p->nfaces].npoints = 3;
- Malloc (p->faces[p->nfaces].points, 3, int);
- p->faces[p->nfaces].points[0] = x;
- p->faces[p->nfaces].points[1] = y;
- p->faces[p->nfaces].points[2] = z;
- p->nfaces++;
-}
-
-static void
-push_face4 (polyhedron *p, int x, int y, int z, int w)
-{
- p->faces[p->nfaces].npoints = 4;
- Malloc (p->faces[p->nfaces].points, 4, int);
- p->faces[p->nfaces].points[0] = x;
- p->faces[p->nfaces].points[1] = y;
- p->faces[p->nfaces].points[2] = z;
- p->faces[p->nfaces].points[3] = w;
- p->nfaces++;
-}
-
-
-
-
-static polyhedron *
-construct_polyhedron (Polyhedron *P, Vector *v, int V, Vector *f, int F,
- const char *name, const char *dual,
- const char *class, const char *star,
- double azimuth, double elevation, double freeze)
-{
- int i, j, k=0, l, ll, ii, *hit=0, facelets;
-
- polyhedron *result;
- Vector *temp;
-
- Malloc (result, 1, polyhedron);
- memset (result, 0, sizeof(*result));
-
- /*
- * Rotate polyhedron
- */
- rotframe(azimuth, elevation, freeze);
- Malloc(temp, V, Vector);
- rotarray(temp, v, V);
- v = temp;
- Malloc(temp, F, Vector);
- rotarray(temp, f, F);
- f = temp;
-
- result->number = P->index + 1;
- result->name = strdup (name);
- result->dual = strdup (dual);
- result->wythoff = strdup (P->polyform);
- result->config = strdup (P->config);
- result->group = strdup (P->group);
- result->class = strdup (class);
-
- /*
- * Vertex list
- */
- Malloc (result->points, V + F * 13, point);
- result->npoints = 0;
-
- result->nedges = P->E;
- result->logical_faces = F;
- result->logical_vertices = V;
- result->density = P->D;
- result->chi = P->chi;
-
- for (i = 0; i < V; i++)
- push_point (result, v[i]);
-
- /*
- * Auxiliary vertices (needed because current VRML browsers cannot handle
- * non-simple polygons, i.e., ploygons with self intersections): Each
- * non-simple face is assigned an auxiliary vertex. By connecting it to the
- * rest of the vertices the face is triangulated. The circum-center is used
- * for the regular star faces of uniform polyhedra. The in-center is used for
- * the pentagram (#79) and hexagram (#77) of the high-density snub duals, and
- * for the pentagrams (#40, #58) and hexagram (#52) of the stellated duals
- * with configuration (....)/2. Finally, the self-intersection of the crossed
- * parallelogram is used for duals with form p q r| with an even denominator.
- *
- * This method do not work for the hemi-duals, whose faces are not
- * star-shaped and have two self-intersections each.
- *
- * Thus, for each face we need six auxiliary vertices: The self intersections
- * and the terminal points of the truncations of the infinite edges. The
- * ideal vertices are listed, but are not used by the face-list.
- *
- * Note that the face of the last dual (#80) is octagonal, and constists of
- * two quadrilaterals of the infinite type.
- */
-
- if (*star && P->even != -1)
- Malloc(hit, F, int);
- for (i = 0; i < F; i++)
- if ((!*star &&
- (frac(P->n[P->ftype[i]]), frax.d != 1 && frax.d != frax.n - 1)) ||
- (*star &&
- P->K == 5 &&
- (P->D > 30 ||
- denominator (P->m[0]) != 1))) {
- /* find the center of the face */
- double h;
- if (!*star && P->hemi && !P->ftype[i])
- h = 0;
- else
- h = P->minr / dot(f[i],f[i]);
- push_point(result, scale (h, f[i]));
-
- } else if (*star && P->even != -1) {
- /* find the self-intersection of a crossed parallelogram.
- * hit is set if v0v1 intersects v2v3*/
- Vector v0, v1, v2, v3, c0, c1, p;
- double d0, d1;
- v0 = v[P->incid[0][i]];
- v1 = v[P->incid[1][i]];
- v2 = v[P->incid[2][i]];
- v3 = v[P->incid[3][i]];
- d0 = sqrt(dot(diff(v0, v2), diff(v0, v2)));
- d1 = sqrt(dot (diff(v1, v3), diff(v1, v3)));
- c0 = scale(d1, sum(v0, v2));
- c1 = scale(d0, sum(v1, v3));
- p = scale(0.5 / (d0 + d1), sum(c0, c1));
- push_point (result, p);
- p = cross(diff(p, v2), diff(p, v3));
- hit[i] = (dot(p, p) < 1e-6);
- } else if (*star && P->hemi && P->index != last_uniform - 1) {
- /* find the terminal points of the truncation and the
- * self-intersections.
- * v23 v0 v21
- * | \ / \ / |
- * | v0123 v0321 |
- * | / \ / \ |
- * v01 v2 v03
- */
- Vector v0, v1, v2, v3, v01, v03, v21, v23, v0123, v0321 ;
- Vector u;
- double t = 1.5;/* truncation adjustment factor */
- j = !P->ftype[P->incid[0][i]];
- v0 = v[P->incid[j][i]];/* real vertex */
- v1 = v[P->incid[j+1][i]];/* ideal vertex (unit vector) */
- v2 = v[P->incid[j+2][i]];/* real */
- v3 = v[P->incid[(j+3)%4][i]];/* ideal */
- /* compute intersections
- * this uses the following linear algebra:
- * v0123 = v0 + a v1 = v2 + b v3
- * v0 x v3 + a (v1 x v3) = v2 x v3
- * a (v1 x v3) = (v2 - v0) x v3
- * a (v1 x v3) . (v1 x v3) = (v2 - v0) x v3 . (v1 x v3)
- */
- u = cross(v1, v3);
- v0123 = sum(v0, scale(dot(cross(diff(v2, v0), v3), u) / dot(u,u),
- v1));
- v0321 = sum(v0, scale(dot(cross(diff(v0, v2), v1), u) / dot(u,u),
- v3));
- /* compute truncations */
- v01 = sum(v0 , scale(t, diff(v0123, v0)));
- v23 = sum(v2 , scale(t, diff(v0123, v2)));
- v03 = sum(v0 , scale(t, diff(v0321, v0)));
- v21 = sum(v2 , scale(t, diff(v0321, v2)));
-
- push_point(result, v01);
- push_point(result, v23);
- push_point(result, v0123);
- push_point(result, v03);
- push_point(result, v21);
- push_point(result, v0321);
-
- } else if (*star && P->index == last_uniform - 1) {
- /* find the terminal points of the truncation and the
- * self-intersections.
- * v23 v0 v21
- * | \ / \ / |
- * | v0123 v0721 |
- * | / \ / \ |
- * v01 v2 v07
- *
- * v65 v4 v67
- * | \ / \ / |
- * | v4365 v4567 |
- * | / \ / \ |
- * v43 v6 v45
- */
- Vector v0, v1, v2, v3, v4, v5, v6, v7, v01, v07, v21, v23;
- Vector v43, v45, v65, v67, v0123, v0721, v4365, v4567;
- double t = 1.5;/* truncation adjustment factor */
- Vector u;
- for (j = 0; j < 8; j++)
- if (P->ftype[P->incid[j][i]] == 3)
- break;
- v0 = v[P->incid[j][i]];/* real {5/3} */
- v1 = v[P->incid[(j+1)%8][i]];/* ideal */
- v2 = v[P->incid[(j+2)%8][i]];/* real {3} */
- v3 = v[P->incid[(j+3)%8][i]];/* ideal */
- v4 = v[P->incid[(j+4)%8][i]];/* real {5/2} */
- v5 = v[P->incid[(j+5)%8][i]];/* ideal */
- v6 = v[P->incid[(j+6)%8][i]];/* real {3/2} */
- v7 = v[P->incid[(j+7)%8][i]];/* ideal */
- /* compute intersections */
- u = cross(v1, v3);
- v0123 = sum(v0, scale(dot(cross(diff(v2, v0), v3), u) / dot(u,u),
- v1));
- u = cross(v7, v1);
- v0721 = sum(v0, scale(dot(cross(diff(v2, v0), v1), u) / dot(u,u),
- v7));
- u = cross(v5, v7);
- v4567 = sum(v4, scale(dot(cross(diff(v6, v4), v7), u) / dot(u,u),
- v5));
- u = cross(v3, v5);
- v4365 = sum(v4, scale(dot(cross(diff(v6, v4), v5), u) / dot(u,u),
- v3));
- /* compute truncations */
- v01 = sum(v0 , scale(t, diff(v0123, v0)));
- v23 = sum(v2 , scale(t, diff(v0123, v2)));
- v07 = sum(v0 , scale(t, diff(v0721, v0)));
- v21 = sum(v2 , scale(t, diff(v0721, v2)));
- v45 = sum(v4 , scale(t, diff(v4567, v4)));
- v67 = sum(v6 , scale(t, diff(v4567, v6)));
- v43 = sum(v4 , scale(t, diff(v4365, v4)));
- v65 = sum(v6 , scale(t, diff(v4365, v6)));
-
- push_point(result, v01);
- push_point(result, v23);
- push_point(result, v0123);
- push_point(result, v07);
- push_point(result, v21);
- push_point(result, v0721);
- push_point(result, v45);
- push_point(result, v67);
- push_point(result, v4567);
- push_point(result, v43);
- push_point(result, v65);
- push_point(result, v4365);
- }
-
- /*
- * Face list:
- * Each face is printed in a separate line, by listing the indices of its
- * vertices. In the non-simple case, the polygon is represented by the
- * triangulation, each triangle consists of two polyhedron vertices and one
- * auxiliary vertex.
- */
- Malloc (result->faces, F * 10, face);
- result->nfaces = 0;
-
- ii = V;
- facelets = 0;
- for (i = 0; i < F; i++) {
- if (*star) {
- if (P->K == 5 &&
- (P->D > 30 ||
- denominator (P->m[0]) != 1)) {
- for (j = 0; j < P->M - 1; j++) {
- push_face3 (result, P->incid[j][i], P->incid[j+1][i], ii);
- facelets++;
- }
-
- push_face3 (result, P->incid[j][i], P->incid[0][i], ii++);
- facelets++;
-
- } else if (P->even != -1) {
- if (hit && hit[i]) {
- push_face3 (result, P->incid[3][i], P->incid[0][i], ii);
- push_face3 (result, P->incid[1][i], P->incid[2][i], ii);
- } else {
- push_face3 (result, P->incid[0][i], P->incid[1][i], ii);
- push_face3 (result, P->incid[2][i], P->incid[3][i], ii);
- }
- ii++;
- facelets += 2;
-
- } else if (P->hemi && P->index != last_uniform - 1) {
- j = !P->ftype[P->incid[0][i]];
-
- push_face3 (result, ii, ii + 1, ii + 2);
- push_face4 (result, P->incid[j][i], ii + 2, P->incid[j+2][i], ii + 5);
- push_face3 (result, ii + 3, ii + 4, ii + 5);
- ii += 6;
- facelets += 3;
- } else if (P->index == last_uniform - 1) {
- for (j = 0; j < 8; j++)
- if (P->ftype[P->incid[j][i]] == 3)
- break;
- push_face3 (result, ii, ii + 1, ii + 2);
- push_face4 (result,
- P->incid[j][i], ii + 2, P->incid[(j+2)%8][i], ii + 5);
- push_face3 (result, ii + 3, ii + 4, ii + 5);
-
- push_face3 (result, ii + 6, ii + 7, ii + 8);
- push_face4 (result,
- P->incid[(j+4)%8][i], ii + 8, P->incid[(j+6)%8][i],
- ii + 11);
- push_face3 (result, ii + 9, ii + 10, ii + 11);
- ii += 12;
- facelets += 6;
- } else {
-
- result->faces[result->nfaces].npoints = P->M;
- Malloc (result->faces[result->nfaces].points, P->M, int);
- for (j = 0; j < P->M; j++)
- result->faces[result->nfaces].points[j] = P->incid[j][i];
- result->nfaces++;
- facelets++;
- }
- } else {
- int split = (frac(P->n[P->ftype[i]]),
- frax.d != 1 && frax.d != frax.n - 1);
- for (j = 0; j < V; j++) {
- for (k = 0; k < P->M; k++)
- if (P->incid[k][j] == i)
- break;
- if (k != P->M)
- break;
- }
- if (split) {
- ll = j;
- for (l = P->adj[k][j]; l != j; l = P->adj[k][l]) {
- for (k = 0; k < P->M; k++)
- if (P->incid[k][l] == i)
- break;
- if (P->adj[k][l] == ll)
- k = mod(k + 1 , P->M);
- push_face3 (result, ll, l, ii);
- facelets++;
- ll = l;
- }
- push_face3 (result, ll, j, ii++);
- facelets++;
-
- } else {
-
- int *pp;
- int pi = 0;
- Malloc (pp, 100, int);
-
- pp[pi++] = j;
- ll = j;
- for (l = P->adj[k][j]; l != j; l = P->adj[k][l]) {
- for (k = 0; k < P->M; k++)
- if (P->incid[k][l] == i)
- break;
- if (P->adj[k][l] == ll)
- k = mod(k + 1 , P->M);
- pp[pi++] = l;
- ll = l;
- }
- result->faces[result->nfaces].npoints = pi;
- result->faces[result->nfaces].points = pp;
- result->nfaces++;
- facelets++;
- }
- }
- }
-
- /*
- * Face color indices - for polyhedra with multiple face types
- * For non-simple faces, the index is repeated as many times as needed by the
- * triangulation.
- */
- {
- int ff = 0;
- if (!*star && P->N != 1) {
- for (i = 0; i < F; i++)
- if (frac(P->n[P->ftype[i]]), frax.d == 1 || frax.d == frax.n - 1)
- result->faces[ff++].color = P->ftype[i];
- else
- for (j = 0; j < frax.n; j++)
- result->faces[ff++].color = P->ftype[i];
- } else {
- for (i = 0; i < facelets; i++)
- result->faces[ff++].color = 0;
- }
- }
-
- if (*star && P->even != -1)
- free(hit);
- free(v);
- free(f);
-
- return result;
-}
-
-
-
-/* External interface (jwz)
- */
-
-void
-free_polyhedron (polyhedron *p)
-{
- if (!p) return;
- Free (p->wythoff);
- Free (p->name);
- Free (p->group);
- Free (p->class);
- Free (p->points);
- if (p->faces)
- {
- int i;
- for (i = 0; i < p->nfaces; i++)
- Free (p->faces[i].points);
- Free (p->faces);
- }
- Free (p);
-}
-
-
-int
-construct_polyhedra (polyhedron ***polyhedra_ret)
-{
- double freeze = 0;
- double azimuth = AZ;
- double elevation = EL;
- int index = 0;
-
- int count = 0;
- polyhedron **result;
- Malloc (result, last_uniform * 2 + 3, polyhedron*);
-
- while (index < last_uniform) {
- char sym[4];
- Polyhedron *P;
-
- sprintf(sym, "#%d", index + 1);
- if (!(P = kaleido(sym, 1, 0, 0, 0))) {
- Err (strerror(errno));
- }
-
- result[count++] = construct_polyhedron (P, P->v, P->V, P->f, P->F,
- P->name, P->dual_name,
- P->class, "",
- azimuth, elevation, freeze);
-
- result[count++] = construct_polyhedron (P, P->f, P->F, P->v, P->V,
- P->dual_name, P->name,
- P->dual_class, "*",
- azimuth, elevation, freeze);
- polyfree(P);
- index++;
- }
-
- *polyhedra_ret = result;
- count++; /* leave room for teapot */
- return count;
-}