/* * (C) Copyright 2005 Arnaud Bailly (arnaud.oqube@gmail.com), * Yves Roos (yroos@lifl.fr) and others. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package rationals.distance; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Computes the geodesic polyhedron with edges of length lower than a given * parameter with all its points on the part of a n-dimensional sphere of radius * 1, center point 0 and positive coordinates. * * @author nono * @version $Id: Geodesic.java 2 2006-08-24 14:41:48Z oqube $ */ public class Geodesic { /* required edge length */ private double eta; /* dimension of the sphere */ private int dim; /* base polyedron */ double[] base; DecimalFormat frm = new DecimalFormat("0.0000"); /** * Create a geodesic object for given parameter. * * @param eta * maximum length of edges. Must be greater than 0 and lower than * sqrt(2) */ public Geodesic(double eta, int dim) { this.eta = eta; this.dim = dim; } class Point { double[] coords = new double[dim]; /** * */ public void normalize() { /* compute norm */ double norm = norm(); if (norm == 1.0 || norm == 0.0) return; /* update coordinates */ for(int i=0;i<dim;i++) coords[i] /= norm; } /** * Returns distance from this points to p. * * @param p * @return */ public double distance(Point p) { double d = 0; for (int i = 0; i < dim; i++) { double dif = coords[i] - p.coords[i]; d += dif * dif; } return Math.sqrt(d); } /** * * @return */ private double norm() { double n = 0.0; for (int i = 0; i < dim; i++) { n += coords[i] * coords[i]; } return Math.sqrt(n); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append('('); for (int i = 0; i < dim; i++) { sb.append(frm.format(coords[i])); if (i < dim - 1) sb.append(','); } sb.append(')'); return sb.toString(); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { Point pt = (Point) obj; for (int i = 0; i < dim; i++) if (coords[i] != pt.coords[i]) return false; return true; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public int hashCode() { int l = 0; for (int i = 0; i < dim; i++) l ^= (long) coords[i] >> 16; return l; } } /** * A facet is made of n points of n coordinates. * * @author nono * @version $Id: Geodesic.java 2 2006-08-24 14:41:48Z oqube $ */ class Facet { List vertices = new ArrayList(); List adj = new ArrayList(); /* * Default constructor */ Facet() { } /** * split a facet of dimension n into n facets from barycenter. * * @return a List of Facet objects */ List split() { List nf = new ArrayList(); Point p1 = null, p2 = null; int n = vertices.size(); Point barycenter = new Point(); /* comput median points on each "border" of facet * each edge has dim-1 points so we must compute * all the barycenters of each group of n-1 edges * */ for (Iterator i = vertices.iterator(); i.hasNext();) { p2 = (Point) i.next(); /* contribution to barycenter */ for (int j = 0; j < dim; j++) { barycenter.coords[j] += p2.coords[j] / (double)n; } } /* compute global barycenter */ barycenter.normalize(); System.err.println("barycenter = "+barycenter); /* compute distance between barycenter and all points */ double d = 0; double dmax = Double.MIN_VALUE; for (Iterator i = vertices.iterator(); i.hasNext();) { p1 = (Point) i.next(); d = p1.distance(barycenter); if (d > dmax) dmax = d; } /* * split facet only if there are points at a distance greater than * eta to the barycenter */ System.err.println("dmax = "+dmax); if (dmax < eta) return nf; /* create facets */ p1 = null; List ret = new ArrayList(); for (int i = 0; i < n; i++) { Facet f = new Facet(); f.vertices.add(barycenter); int j = 0; for (Iterator it = vertices.iterator(); it.hasNext(); j++) { p2 = (Point) it.next(); if (j == i) continue; f.vertices.add(p2); } ret.add(f); } return ret; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append('['); for (Iterator i = vertices.iterator(); i.hasNext();) { sb.append(i.next()); if (i.hasNext()) sb.append(','); } sb.append(']'); return sb.toString(); } } /** * Computes and return the polyedron for this geodesic sphere. * * @return a List of arrays of double as points on the sphere s.t. */ public Collection getPolyedron() { Set s = new HashSet(); List l = new ArrayList(); List ret = new ArrayList(); l.add(makeSimplex()); do { ret.clear(); for (Iterator i = l.iterator(); i.hasNext();) { Facet f = (Facet) i.next(); for (Iterator j = f.vertices.iterator(); j.hasNext();) { Geodesic.Point pt = (Geodesic.Point) j.next(); s.add(pt); } List nl = f.split(); if (!nl.isEmpty()) { i.remove(); ret.addAll(nl); } } if (!ret.isEmpty()) { l.clear(); l.addAll(ret); } } while (!ret.isEmpty()); return s; } /** * Returns a collection of facets representing the simplex of * the hypersphere surface. * * @return */ private Collection makeSimplex() { /* * initialize things - we start with minimal simplex in * n dimensions */ List pts = new ArrayList(); List ret = new ArrayList(); int n = dim; /* limit points */ for (int i = 0; i < n; i++) { Point pt = new Point(); for (int j = 0; j < n; j++) pt.coords[j] = (i == j) ? (base != null) ? base[i] : 1 : 0; pts.add(pt); } Point barycenter = new Point(); /* barycenter */ for (Iterator i = pts.iterator(); i.hasNext();) { Point p2 = (Point) i.next(); /* contribution to barycenter */ for (int j = 0; j < n; j++) { barycenter.coords[j] += p2.coords[j] / (double)n; } } barycenter.normalize(); /* construct facets */ for(int i=0;i<n;i++) { Facet f = new Facet(); for(int j=0;j<n;j++) { } } return ret; } /** * @return Returns the base. */ public double[] getBase() { return base; } /** * @param base * The base to set. */ public void setBase(double[] base) { this.base = base; } }