package ddddbb.comb; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Vector; import ddddbb.math.D3Graphics; import ddddbb.math.OHalfSpace; import ddddbb.math.Point; import ddddbb.math.Point3d; public class Cell extends ACell { protected Vector<OCell> facets = new Vector<OCell>(); //dim-1 //this cell is referenced from the following OCells protected HashSet<OCell> referrers = new HashSet<OCell>(); //dim Location location; SpaceId spaceId; protected Cell inner; // dim protected Cell outer; // dim /* innerCut and outerCut are copies, they dont belong to any other facets */ protected Cell cut; protected Vector<Cell> contained_facets; /** use the projection to 3d space for computations, regardless of spaceDim */ //public boolean as3d = true; protected int splitCellIs = PRISTINE; public static final int SPLITTED = 0; public static final int INNER = -1; public static final int OUTER = 1; public static final int CONTAINED = 2; public static final int PRISTINE = 3; // private boolean internal = false; public Cell(double[][][] _facets) { this(pointCells(_facets),new Vector<Cell>(),new Vector<Cell>(),new Vector<Cell>()); } private Cell(Cell[][][] _facets, Vector<Cell> f2, Vector<Cell> f1, Vector<Cell> f0) { location = new Location(_facets[0][0][0].spaceDim(),3); spaceId = new SpaceId(); for (Cell[][] f: _facets) { Cell c = lookup(f2,new Cell(f,f1,f0)); new OCell(c,this);//this is twice } assert checkClosed(); } private Cell(Cell[][] _facets, Vector<Cell> f1, Vector<Cell> f0) { location = new Location(_facets[0][0].spaceDim(),2); spaceId = new SpaceId(); for (Cell[] f: _facets) { Cell c = lookup(f1,new Cell(f,f0)); OCell fcell = new OCell(c,this);//this is twice assert c.checkFaces(); assert fcell.checkFaces(); } assert checkClosed(); for (OCell oc:facets) { assert oc.checkFaces(); } } private Cell(Cell[] ab, Vector<Cell> f0) { location = new Location(ab[0].spaceDim(),1); spaceId = new SpaceId(); assert ab.length == 2 : ab.length; new OCell(lookup(f0,ab[0]),this); new OCell(lookup(f0,ab[1]),this); assert facets().size() == 2 : facets().size(); assert checkClosed(); assert checkFaces(); } public static <A> A lookup(Vector<A> list,A src) { for (A p:list) { if (p.equals(src)) { return p; } } list.add(src); return src; } public boolean equals(Object o) { Cell c = (Cell)o; if (dim()!=c.dim()) { return false; } if (dim()==0) { return location.equals(c.location); } if (facets.size()!=c.facets.size()) { return false; } for (int i=0;i<facets.size();i++) { boolean found = false; for (int j=0;j<facets.size();j++) { if (facets.get(i).cell().equals(c.facets.get(j).cell())) { found = true; break; } } if (!found) { return false; } } return true; } public static Cell[][][] pointCells(double[][][] x) { Cell[][][] res = new Cell[x.length][][]; for (int i=0;i<x.length;i++) { res[i] = new Cell[x[i].length][2]; for (int j=0;j<x[i].length;j++) { assert x[i][j].length == 6; res[i][j][0] = new Cell(new Point3d(x[i][j][0],x[i][j][1],x[i][j][2]),new SpaceId()); res[i][j][1] = new Cell(new Point3d(x[i][j][3],x[i][j][4],x[i][j][5]),new SpaceId()); } } return res; } public Cell(Point point, SpaceId _spaceId) { location = new Location(point,true); spaceId = _spaceId; } protected Cell() {} // public Cell(Location _location) { // assert _location.dim() == 0; // location = _location; // } // public Cell(Location a, Location b) { // location = new Location(3,1); // new OCell(new Cell(a),this,-1); // new OCell(new Cell(b),this,+1); // } /** Make a cell out of the given _facets, * Changes their parents to this cell! */ // private Cell(Collection<OCell> _facets,boolean _dummy) { // assert ! _facets.isEmpty(); // assert _facets.iterator().next() != null : // null; // location = new Location(3,_facets.iterator().next().dim()+1); // // for (OCell of: _facets) { // of.connectParent(this); // } // assert checkFacetsDim(); // if ( ! checkClosed() ) { // assert false; // } // assert dim() != 1 || facets().size() == 2 : facets().size(); // } // public static Cell create(Collection<OCell> facets, SpaceId _spaceId) { Cell c = new Cell(); assert ! facets.isEmpty(); assert facets.iterator().next() != null : null; c.location = new Location(3,facets.iterator().next().dim()+1); c.spaceId = _spaceId; for (OCell of: facets) { of.connectParent(c); } assert c.checkFacetsDim(); if ( ! c.checkClosed() ) { assert false; } assert c.dim() != 1 || c.facets().size() == 2 : c.facets().size(); return c; } private Cell(Collection<Cell> _facets, SpaceId _spaceId) { //weird: Java can not distinguish between List<Cell> and List<OCell> assert ! _facets.isEmpty(); location = new Location(3,_facets.iterator().next().dim()+1); spaceId = _spaceId; for (Cell f :_facets) { new OCell(f,this); } assert checkFacetsDim(); if ( ! checkClosed() ) { assert false; } assert dim() != 1 || facets.size() == 2 : facets; } public List<? extends BCell> facets() { Vector<OCell> res = new Vector<OCell>(); for (OCell f:facets) { res.add(f); } return res; } public boolean isSplitted() { return splitCellIs == SPLITTED; } public boolean isInner() { return splitCellIs == INNER; } public boolean isOuter() { return splitCellIs == OUTER; } public boolean isContained() { return splitCellIs == CONTAINED; } // public List<Cell> facets() { // Vector<Cell> res = new Vector<Cell>(); // for ( FragmentedCell f : facets) { // res.add(f.shape()); // } // return res; // } /** returns a copy of the normal of this Cell */ public Point normal() { assert spaceId.normal.isNormal(); return spaceId.normal.clone(); } public ALocation location() { return location; } //temporarily //public Space2d space2d; public void computeSpacesIN() { assert spaceDim() == 3 : spaceDim(); assert dim() == 3; Collection<ALocation> locations = getPointLocations(false); for (OCell f2:facets) { assert f2.cell().halfSpaces() != null || f2.orientation == 0 : f2.cell().halfSpaces() + "|" + f2.orientation; f2.cell().computeSpace2dIN(); if (f2.orientation != 0) { continue; } f2.orientation = +1; for ( ALocation l : locations ) { if ( f2.cell().spaceId.side(l.o()) == 1 ) { f2.orientation = -1; break; } } } } public void computeSpace2dIN() { assert spaceDim() == 3; assert dim() == 2; if (spaceId.spaceComputed) { return; } spaceId.setHalfSpace(facets); } private Point cutPoint(OHalfSpace e) { assert spaceDim() == 3; assert dim() == 1; Point a = a().o(); Point b = b().o(); double ad = e.dist(a); double bd = e.dist(b); return e.proj(a).multiply(bd/(ad+bd)).add(e.proj(b).multiply(ad/(ad+bd))); } // /** INNER means INNER with possible touch // * OUTER means OUTER with possible touch // */ // public int side(Space2d e, int orientation) { // assert spaceDim() == 3; // Collection<ALocation> locations = getPointLocations(false); // int side = PRISTINE; // for ( ALocation l : locations ) { // if ( e.outer(l.p3)*orientation == -1 ) { //inner // if ( side == PRISTINE ) { side = INNER; continue; } // if ( side == CONTAINED ) { side = INNER; continue; } // if ( side == OUTER ) { return SPLITTED; } // // unchanged for side==INNER // continue; // } // if ( e.outer(l.p3)*orientation == 1 ) { // if ( side == PRISTINE ) { side = OUTER; continue; } // if ( side == CONTAINED ) { side = OUTER; continue; } // if ( side == INNER) { return SPLITTED; } // // unchanged for side==OUTER // continue; // } // if ( e.outer(l.p3) == 0 ) { // if ( side == PRISTINE ) { side = CONTAINED; continue; } // //unchanged for side == INNER, OUTER, CONTAINED // continue; // } // } // return side; // } public void split(OHalfSpace e,OCell referer) { assert spaceId !=null : dim(); assert referer==null || referrers.contains(referer); assert e != null; if ( isSplitted()) { return; } Set<Cell> cut_facets = new HashSet<Cell>(); // dim - 2 Vector<OCell> inner_facets = new Vector<OCell>(); // dim - 1 Vector<OCell> outer_facets = new Vector<OCell>(); // dim - 1 OCell innerCut = null; OCell outerCut = null; //if this cell was split, it will no more be used //if it however was only touched, it will be reused and so we have to //ascertain that the variables are in the initial state cut = null; inner = null; outer = null; splitCellIs = PRISTINE; contained_facets = new Vector<Cell>(); // dim - 1 assert checkFaces(); inner = null; outer = null; if ( dim() == 0 ) { Point p = o(); if (e.outer(p) == -1 ) { splitCellIs = INNER; return; } if (e.outer(p) == 1 ) { splitCellIs = OUTER; return; } assert e.outer(p) == 0; splitCellIs = CONTAINED; return; } else if ( dim() == 1 ) { assert facets().size() == 2; OCell af = facets.get(0); OCell bf = facets.get(1); Point a = af.cell().location.p3; Point b = bf.cell().location.p3; int sideA = e.outer(a); int sideB = e.outer(b); if (sideA==-1 && sideB== 1) { cut = new Cell(cutPoint(e),spaceId.cut(e.space())); inner_facets.add(af); outer_facets.add(bf); splitCellIs = SPLITTED; //continue below } else if (sideA== 1 && sideB==-1) { cut = new Cell(cutPoint(e),spaceId.cut(e.space())); inner_facets.add(bf); outer_facets.add(af); splitCellIs = SPLITTED; //continue below } else if (sideA== 0 && sideB== 1) { contained_facets.add(a()); splitCellIs = OUTER; return; } else if (sideA== 1 && sideB== 0) { contained_facets.add(b()); splitCellIs = OUTER; return; } else if (sideA== 0 && sideB==-1) { contained_facets.add(a()); splitCellIs = INNER; return; } else if (sideA==-1 && sideB== 0) { contained_facets.add(b()); splitCellIs = INNER; return; } else if (sideA== 0 && sideB== 0) { splitCellIs = CONTAINED; return; } else if (sideA== 1 && sideB== 1) { splitCellIs = OUTER; return; } else if (sideA==-1 && sideB==-1) { splitCellIs = INNER; return; } assert splitCellIs == SPLITTED; } else { assert dim() > 1; for (OCell of : facets) { Cell f = of.cell(); assert of.parent() == this; of.cell().split(e,of); assert of.cell().referrers.contains(of); if ( f.isSplitted()) { inner_facets.add(of.inner); outer_facets.add(of.outer); cut_facets.add(f.cut); } else if ( f.isInner() ) { inner_facets.add(of); cut_facets.addAll(f.contained_facets); } else if ( f.isOuter() ) { outer_facets.add(of); cut_facets.addAll(f.contained_facets); } else if ( f.isContained()) { contained_facets.add(f); } else { assert false; } } if (inner_facets.isEmpty() && outer_facets.isEmpty()) { assert contained_facets.size() == facets.size(); splitCellIs = CONTAINED; assert checkFaces(); return; } else if (inner_facets.isEmpty()) { assert contained_facets.size() < facets().size() : contained_facets + "|" + facets(); splitCellIs = OUTER; assert checkFaces(); return; } else if (outer_facets.isEmpty()) { assert contained_facets.size() < facets().size(); splitCellIs = INNER; assert checkFaces(); return; } else if ((! inner_facets.isEmpty()) && (! outer_facets.isEmpty())) { cut = new Cell(cut_facets,spaceId.cut(e.space())); splitCellIs = SPLITTED; //continue below } else { assert false; } assert splitCellIs == SPLITTED; } assert splitCellIs == SPLITTED; innerCut = new OCell(cut); outerCut = new OCell(cut); inner_facets.add(innerCut); outer_facets.add(outerCut); inner = create(inner_facets,spaceId); outer = create(outer_facets,spaceId); if (dim()==spaceDim()) { outerCut.orientation = -e.orientation(); innerCut.orientation = e.orientation(); } assert OCell.opposite(innerCut, outerCut); assert innerCut.snappedTo() == outerCut; assert referer==null || referrers.contains(referer); for (OCell oc:referrers) { oc.breakOpen(); //dont catch the parents that we just iterating if (oc==referer) { continue; } if (oc.parent()!=null) { int i = oc.parent().facets.indexOf(oc); oc.parent().facets.set(i,oc.inner); oc.parent().facets.add(oc.outer); } } assert innerCut.location() == outerCut.location(); assert inner_facets.iterator().next().dim() == innerCut.dim() : inner_facets.iterator().next().dim() + "," + innerCut.dim(); assert inner.checkFaces(); assert outer.checkFaces(); return; } public void snapOut() { for (OCell f: facets) { f.snapOut(); } } /** Removes all references to this and removes resulting unreferenced cells */ public void remove() { for (OCell f: facets) { // f.nullifyParent(); HashSet<OCell> frefs = f.cell().referrers; frefs.remove(f); if (frefs.isEmpty()) f.cell().remove(); } // facets.clear(); for (OCell r:referrers) { r.nullifyCell(); } // referrers.clear(); } /** Convenience for 1d cell, returns the first point */ public Cell a() { assert dim() == 1; return facets.get(0).cell(); } /** Convenience for 1d cell, returns the second point */ public Cell b() { assert dim() == 1; return facets.get(1).cell(); } /** paints this facet onto g3 assuming that it was already * 3-projected */ public void paint(D3Graphics g3, boolean woInternals) { if (isInternal() && woInternals) { return; } if (isSplitted()) { inner.paint(g3, woInternals); outer.paint(g3, woInternals); return; } if (dim()==1) { g3.drawLine((Point3d)a().o(), (Point3d)b().o()); return; } for (OCell f : facets) { f.paint(g3,woInternals); } } /** * returns all unhidden faces of dimension d * @param d dimension * @return Collection of faces */ public Collection<Cell> getFaces(int d,boolean withInternalFaces) { HashSet<Cell> res = new HashSet<Cell>(); if (!withInternalFaces && isInternal()) { return res; } if (d>dim()) { return res; } if (d==dim()) { res.add(this); return res; } for (OCell f: facets) { res.addAll(f.cell().getFaces(d,withInternalFaces)); } return res; } public Collection<Cell> getFacesDownTo(int d, boolean withInternalFaces) { HashSet<Cell> res = new HashSet<Cell>(); if (!withInternalFaces && isInternal()) { return res; } if (d>dim()) { return res; } res.add(this); for (OCell f: facets) { assert f.cell() != null; res.addAll(f.cell().getFacesDownTo(d,withInternalFaces)); } return res; } public void addAllFaces(HashSet<OCell> res) { for (OCell o: facets) { o.cell().addAllFaces(res); } return; } public Point center() { Point center = Point.create(spaceDim()); int n=0; for (OCell f: facets) { center.add(f.cell().center()); n++; } center.multiply(1.0/n); return center; } public Point3d center3d() { if (dim()==0) { return (Point3d)o(); } Point3d center = new Point3d(); int n=0; for (OCell f: facets) { center.add(f.cell().center3d()); n++; } center.multiply(1.0/n); return center; } // public Vector<Cell> cutOut(Iterable<OHalfSpace> planes) { // Vector<Cell> res = new Vector<Cell>(); // // /* If this cell is outside one of the planes there is nothing to do*/ // for (OHalfSpace e:planes) { // if (e.side(this) == Cell.OUTER) { // res.add(this); // return res; // } // } // // /* Otherwise it will be cut into pieces */ // // Cell innerCell = this; // // for (OHalfSpace e:planes) { // innerCell.split(e,null); // res.add(innerCell.outer); // innerCell = innerCell.inner; // assert innerCell.checkPointRefs() : // innerCell.getPointLocations(); // } // // assert innerCell != null; // innerCell.snapOut(); // return res; // } public boolean isInternal() { // if it is not referenced from anywhere it is a top level cell and visible if (referrers.size()==0) { return false; } /* go through the OCells that refer to this Cell and determine * whether they are all internal * If only one is visible this whole Cell is visible */ for (OCell oc:referrers) { if (!oc.isInternal()) return false; assert oc.snappedTo() ==null || referrers.contains(oc.snappedTo()); } return true; } // public String toString() { // if (dim()==0) { // return o().toString(); // } // if ( dim() == 1 ) { // return "[" + a() + "," + b() + "]"; // } // return facets.toString(); // } protected boolean checkFacetsDim() { for (ACell fm1: facets()) { if (fm1.dim() != dim() -1) { return false; } } return true; } public Cell inner() { return inner; } public Cell outer() { return outer; } boolean checkSnap() { for (OCell f: facets) { if ( ! f.checkSnap() ) { return false; } } return true; } public boolean checkPointRefs() { Vector<ALocation> pointrefs = getPointLocations(); for (int i=0;i<pointrefs.size();i++) { for (int j=i+1;j<pointrefs.size();j++) { if (pointrefs.get(i)!=pointrefs.get(j) && pointrefs.get(i).equals(pointrefs.get(j))) { System.out.println(""+pointrefs.get(i)+pointrefs.get(i).hashCode()+pointrefs.get(j)+pointrefs.get(j).hashCode()); return false; } } } return true; } public boolean checkCellrefs() { Vector<OCell> cellrefs = new Vector<OCell>(); return checkCellrefs(cellrefs); } public boolean checkCellrefs(Vector<OCell> cellrefs) { for (OCell of:facets) { Cell f = of.cell(); for (OCell or:cellrefs) { Cell r=or.cell(); if ( f!=r && f.equals(r)) { assert or.src.location()._dst == or.cell(); System.out.println(or+""+or.src + "" + or.src.location().hashCode()); System.out.println(of+""+of.src + "" + of.src.location().hashCode()); assert false: false; } } assert f.checkCellrefs(cellrefs); cellrefs.add(of); } return true; } public boolean checkSnapCell() { for(OCell of:facets) { if (! of.checkSnapCell()) { return false; } } return true; } public HashSet<SpaceId> halfSpaces() { HashSet<SpaceId> res = new HashSet<SpaceId>(); if (dim()==spaceDim()) { return res; } if (dim()+1==spaceDim()) { res.add(spaceId); return res; } for (OCell oc:referrers) { res.addAll(oc.parent().halfSpaces()); } return res; } public HashSet<OCell> getReferrers() { return referrers; } public SpaceId getSpace() { return spaceId; } }