package ddddbb.comb; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Vector; import ddddbb.math.Camera4d; import ddddbb.math.D3Graphics; import ddddbb.math.Point; import ddddbb.math.Camera4d.ProjectionException; /** * A class that represents an oriented integer facet, i.e. a facet of a (hyper)cube * with integer coordinates and each side length 1. * A toplevel facet is defined as having the same number of dimensions * as the surrounding space and having no parents. * @author bo198214 * */ public class DCell extends BCell { public static class Cube extends DCell { public Cube(int[] coords, Vector<DLocation>[] _locations) { super(4); normal = new DSignedAxis(1,-1); parent = null; location = new DLocation(DOp.clone(coords),new int[] {0,1,2,3}); initialize(_locations); } } public DLocation location; private int dim; DSignedAxis normal; //normal vector for this facet, points outside public DCell[][] facets = new DCell[2][]; DCell parent = null; /** * The neighbor facet of this facet in a compound. * That is an adjacent facet * of same orientation located in the same subspace */ public DCell neighbor = null; public boolean isInternal0() { return neighbor != null; } public boolean isInternal() { if ( neighbor != null ) { if ( neighbor.parent != null ) { return ! neighbor.parent.isInternal(); } return true; // snappedTo().parent() == null } return false; // snappedTo == null // return snappedTo() != null; } protected DCell(int _dim) { dim = _dim; if (dim==0) { facets = null; } else { for (int s=0;s<2;s++) { facets[s] = new DCell[dim]; for (int ai=0;ai<dim;ai++) { facets[s][ai] = new DCell(dim-1); facets[s][ai].parent = this; } } } } public DCell(DCell f) { dim = f.dim; normal = f.normal; parent = f.parent; for (int s=0;s<2;s++) { facets[s] = new DCell[dim]; for (int a=0;a<dim;a++) { facets[s][a] = f.facets[s][a]; } } location = f.location; } protected void initialize(List<DLocation>[] locations) { if (locations[dim].contains(location)) { location = locations[dim].get(locations[dim].indexOf(location)); } else { locations[dim].add(location); } if (dim==0) { return; } assert dim == location.spat.length; assert dim == facets[0].length; for (int s=0;s<2;s++) { for (int ai=0;ai<dim;ai++) { int[] faceSpat = new int[dim-1]; for (int j=0;j<dim-1;j++) { if (j<ai) { faceSpat[j] = location.spat[j]; } else { faceSpat[j] = location.spat[j+1]; } } int[] faceOrigin = DOp.clone(location.origin); faceOrigin[location.spat[ai]] += s; DCell f = facets[s][ai]; f.normal =new DSignedAxis(s,location.spat[ai]); f.location = new DLocation(faceOrigin,faceSpat); f.initialize(locations); } } } @Override public Point normal() { if (dim()+1==spaceDim()) { int[] normals = location.coSpace(); assert normals.length==1; int n = normals[0]; assert normal.axis == n; if (neighbor!=null) { assert normal.pos == ! neighbor.normal.pos; } } return normal.direc(spaceDim()); } private void originUpdate() { if (dim==0) { return; } for (int s=0;s<2;s++) { for (int ai=0;ai<dim;ai++) { int[] faceSpat = new int[dim-1]; for (int j=0;j<dim-1;j++) { if (j<ai) { faceSpat[j] = location.spat[j]; } else { faceSpat[j] = location.spat[j+1]; } } int[] faceOrigin = DOp.clone(location.origin); faceOrigin[location.spat[ai]] += s; DCell f = facets[s][ai]; f.normal =new DSignedAxis(s,location.spat[ai]); f.location.origin = faceOrigin; f.location.spat = faceSpat; f.originUpdate(); } } } public void rotate2(DCenter o,int v,int w) { DCenter c = new DCenter(location.origin); c.rotate(o,v,w); location.origin = c.origin(); originUpdate(); } public void rotate(DCenter o,int v,int w) { assert v!=w; if (normal.axis==v) { normal.axis=w; } else if (normal.axis==w) { normal=new DSignedAxis(!normal.pos,v); } if (dim==0) { return; } for (int s=0;s<2;s++) { for (int ai=0;ai<dim;ai++) { facets[s][ai].rotate(o,v,w); //Dont rotate locations, its separately done on locations } } } // /** computes the arithmetic center of the facet */ // public double[] center() { // int[] coords = origin(); // double[] res = new double[dim]; // for (int i=0;i<coords.length;i++) { // res[i] = coords[i]; // } // int[] spat = spat(); // for (int a=0;a<spat.length;a++) { // res[a]+=0.5; // } // return res; // } // /** gets the vertex v of a facet * such that v+0.5*spat() is the center of that facet */ public int[] origin() { return location.origin; } /** returns the axes which span the facet */ public int[] spat() { return location.spat; } /** returns the axes which are orthogonal to the facet */ public int[] orth() { int[] res = new int[spaceDim()-dim]; int[] spat = spat(); for (int a=0,ind=0;a<spaceDim();a++) { boolean inSpat = false; for (int i=0;i<spat.length;i++) { if (spat[i]==a) { inSpat = true; break; } } if (!inSpat) { res[ind]=a; ind++; } } return res; } public int[] path() { if (parent==null) { return new int[0]; } int[] pp = parent.path(); int[] res = new int[pp.length+1]; for (int i=0;i<pp.length;i++) { res[i] = pp[i]; } res[pp.length]=normal.axis; return res; } public int coord() { if (normal.axis==-1||parent==null) { return 0; } return origin()[normal.axis]; } public List<Point> vertices() { Vector<Point> v = new Vector<Point>(); if (dim==0) { v.add(Point.create(vertex())); return v; } for (int s=0;s<2;s++) { v.addAll(facets[s][0].vertices()); } return v; } public int spaceDim() { if (parent==null) { return dim; } return parent.spaceDim(); } // private Vector<Point> spat(Projection t) { // int[] o = origin(); // int d = o.length; // Vector<Point> v = new Vector<Point>(); // int[] spat = spat(); // for (int i=0;i<spat.length;i++) { // // Point p2 = Point.create(t.toDim()); // t.proj(o,p2); // Point p1 = Point.create(t.toDim()); // t.proj(DOp.plus(o,DOp.unitVector(i,d)),p1); // Point p = Point.create(t.toDim()); // p = p1.clone().subtract(p2); // v.add(p.clone().multiply(1/p.len())); // } // return v; // } // public Vector<Point> orth(Projection t) { // int[] o = origin(); // int d = o.length; // Vector<Point> v = new Vector<Point>(); // int[] orth = orth(); // for (int i=0;i<orth.length;i++) { // Point s = // t.proj(DOp.plus(o,DOp.unitVector(i,d))).minus(t.proj(o)); //// Iterator spatIt = spat(t).iterator(); //// while (spatIt.hasNext()) { //// Point dir = (Point) spatIt.next(); //// s = s.minus(dir.proj(Point.create(o))); //// } // v.add(s.times(1/s.len())); // } // return v; // } // /** // * computes the axis in toplevel space // * toplevel facet (i.e. parent==null) has no axis // */ // public int axis() { //// int[] orth = orth(); //// return orth[orth.length-1]; // if (parent==null) { return axisIndex; } // return parent.location.spat[axisIndex]; // } /** returns the vertex of an 0 dimensional Facet */ public int[] vertex() { return location.origin; } public static boolean positionEqual(DCell f1,DCell f2) { return f1.location == f2.location; } public static int signum(int direction ) { return (direction % 2)*2 - 1; } public double faceDistance(double[] eye) { // int axis = axis(); return location.origin[normal.axis]-eye[normal.axis]; } public Collection<DCell> getFacets(boolean all) { return getFaces(dim-1,all); } public static Collection<DCell> getFacets(Collection<DCell> v,boolean withInternalFaces) { if (v.isEmpty()) { return v; } DCell f = v.iterator().next(); return getFaces(f.dim-1,v,withInternalFaces); } /** * returns all unhidden faces of dimension d * @param d dimension * @return Collection of facets */ public Collection<DCell> getFaces(int d,boolean withInternalFaces) { Collection<DCell> res = new Vector<DCell>(); if (!withInternalFaces && isInternal()) { return res; } if (d>dim) { return res; } if (d==dim) { res.add(this); return res; } for (int s=0;s<2;s++) for (int a=0;a<dim;a++) { DCell f = facets[s][a]; res.addAll( f.getFaces(d,withInternalFaces)); } return res; } public static Collection<DCell> getFaces(int d,Collection<DCell> v,boolean all) { Collection<DCell> res = new Vector<DCell>(); for (DCell f : v) { res.addAll(f.getFaces(d,all)); } return res; } /* * returns the faces of all dimensions * untested and unused */ public Collection<DCell> getAllFaces() { Collection<DCell> res = new Vector<DCell>(); if (dim==0) { return res; } for (int s=0;s<2;s++) for (int a=0;a<dim;a++) { DCell f = facets[s][a]; res.add(f); res.addAll(f.getAllFaces()); } return res; } private static class FacetVectorByInt extends HashMap<Integer,Vector<DCell>> { private static final long serialVersionUID = 3005137881365448845L; public void add(int i,DCell f) { Vector<DCell> v = get(i); if (v == null ) { v = new Vector<DCell>(); put(i,v); } v.add(f); } public Vector<DCell> get(int i) { Integer index = new Integer(i); Vector<DCell> v = get(index); return v; } public void put(int i,Vector<DCell> v) { Integer index = new Integer(i); put(index,v); } } public static boolean pathEqual(DCell a,DCell b) { // a facet without parent has no sign and no axis //but it has an origin and orthogonals/spat if (a.parent==null||b.parent==null) { int[] orth = a.orth(); if (!DOp.setEqual(orth,b.orth())) { return false; } int[] a0 = a.origin(); int[] b0 = b.origin(); for (int i=0;i<orth.length;i++) { if (a0[orth[i]]!=b0[orth[i]]) { return false; } } return true; } return a.dim == b.dim && DSignedAxis.equal(a.normal,b.normal) && a.coord()==b.coord() && pathEqual(a.parent,b.parent) ; } public static boolean opposite(DCell a,DCell b) { if (a.normal.axis!=b.normal.axis) { return false; } if (!positionEqual(a,b)) { return false; } if (a.parent==null) { return false; } if (b.parent==null) { return false; } boolean oppSign = a.normal.pmSign()*b.normal.pmSign()==-1; if (oppSign) { return pathEqual(a.parent,b.parent); } if (!oppSign) { return opposite(a.parent,b.parent); } assert false; return true; } /** top-down hides opposite facets * all subfacets of a hidden made facet remain untouched */ public static void markInternalFacets( // int dim, DCell[] facets) { int dim = facets[0].dim; for (int a=0;a<dim;a++) { FacetVectorByInt[] facetsByCoord = { new FacetVectorByInt(), new FacetVectorByInt() }; for (int s=0;s<2;s++) { for (int i=0;i<facets.length;i++) { DCell f0 = facets[i]; DCell fa = f0.facets[s][a]; int coord = f0.coord(); facetsByCoord[s].add(coord,fa); for (int j=i+1;j<facets.length;j++) { DCell f1 = facets[j]; DCell fb = f1.facets[1-s][a]; if (coord!=f1.coord()) { assert !opposite(fa,fb); continue; } // System.out.println("i:"+i+" j:"+j+" s:"+s+" a:"+a); if (positionEqual(fa,fb)) { assert(opposite(fa,fb)); fa.neighbor = fb; // System.out.println("h:"+fa); fb.neighbor = fa; // f0.faces[s][a] = null; // f1.faces[1-s][a] = null; continue; } } } } for (int s=0;s<2;s++) { for (Vector<DCell> v : facetsByCoord[s].values()) { int removed = 0; for (int i=0;i<v.size();i++) { DCell f = v.get(i); if (f.isInternal()) { removed++; } } int n = v.size()-removed; if (n<2) { continue; } DCell[] subFacets = new DCell[n]; for (int i=0,k=0;i<v.size();i++) { DCell f = v.get(i); if (!f.isInternal()) { subFacets[k]=f; k++; } } markInternalFacets(subFacets); } } } } public Collection<DLocation> getLocations() { Vector<DLocation> v = new Vector<DLocation>(); for (int s=0;s<2;s++) for (int a=0;a<dim;a++) { v.addAll(facets[s][a].getLocations()); } return v; } private void setAllExternal() { neighbor = null; for (int s=0;s<2;s++) for (int a=0;a<dim;a++) { facets[s][a].setAllExternal(); } } public static void setAllExternal(DCell[] facets) { for (int i=0;i<facets.length;i++) { facets[i].setAllExternal(); } } public void translate(DSignedAxis v) { location.translate(v); for (int s=0;s<2;s++) for (int a=0;a<dim;a++) { facets[s][a].translate(v); } } public List<DCell> facets() { assert facets != null || dim == 0; Vector<DCell> v = new Vector<DCell>(); if (dim == 0) { return v; } for (int i=0;i<2;i++) { for (DCell f: facets[i]) { v.add(f); } } return v; } public BCell snappedTo() { return neighbor; } public int dim() { return dim; } @Override public Point o() { return Point.create(location.origin); } @Override public ALocation location() { return location; } @Override public ACell parent() { return parent; } public String toString() { // if (dim()==0) { // String res = "("; // for (int i=0;i<location.origin.length;i++) { // res += location.origin[i] + ","; // } // res += ")"; // return res; // } // return facets.toString(); return DOp.toString(parent.location.origin) + ":" + DOp.toString(location.spat); } DSpace space() { return new DSpace(location); } public void proj3d2dIN(D3Graphics g3,Camera4d camera4d) throws ProjectionException { if (dim()==0) { location.proj3d2dIN(g3, camera4d); return; } for (int s=0;s<facets.length;s++) for (int i=0;i<facets[s].length;i++) { facets[s][i].proj3d2dIN(g3,camera4d); } } }