package ddddbb.comb;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import ddddbb.game.Main;
import ddddbb.math.D3Graphics;
import ddddbb.math.Point;
import ddddbb.math.Point3d;
public class OCell extends BCell implements Iterable<OCell> {
protected Cell cell;
protected Cell parent;
protected int orientation = 0; // +1 or -1
private boolean outsnapped = false;
public OCell(Cell _cell, Cell _parent) {
connectCell(_cell);
connectParent(_parent);
}
public OCell(Cell _cell) {
connectCell(_cell);
}
public OCell(Cell _cell,OCell _template) {
fillO(_template);
connectCell(_cell);
}
protected void connectCell(Cell _cell) {
cell = _cell;
cell.referrers.add(this);
assert cell.referrers.contains(this);
}
public void nullifyParent() {
parent = null;
}
public Cell cell() {
return cell;
}
public void nullifyCell() {
cell = null;
}
public void connectParent(Cell _parent) {
parent = _parent;
parent.facets.add(this);
}
/** Copies only the O relevant details into the current OCell from c */
private void fillO(OCell c) {
orientation = c.orientation;
outsnapped = c.outsnapped;
parent = c.parent;
}
protected OCell inner;
protected OCell outer;
protected int splitCellIs = Cell.PRISTINE;
public boolean isSplitted() {
return splitCellIs == Cell.SPLITTED;
}
public boolean isInnerCut() {
return splitCellIs == Cell.INNER;
}
public boolean isOuter() {
return splitCellIs == Cell.OUTER;
}
public boolean isContained() {
return splitCellIs == Cell.CONTAINED;
}
@Override
public Cell parent() {
return parent;
}
public String toString() {
String snapMark = "";
if ( outsnapped ) {
snapMark = "x";
}
return super.toString() + snapMark;
}
public static <T> boolean setEqual(Collection<T> alist,Collection<T> blist) {
if (alist.size()!=blist.size()) { return false; }
for (T a:alist) {
boolean contained = false;
for (T b:blist) {
if (a==b) {
contained = true;
break;
}
}
if (!contained) { return false; }
}
return true;
}
public static boolean adjacent(OCell a,OCell b) {
return a.cell == b.cell;
}
/**
* Two OCells are opposite if they are not equal,
* reference the same Cell
* (i.e. occupy the same location)
* and their parent Cells lie in the same space (same SpaceId),
* but dont occupy the same location.
* In this case they are not visible per default.
*/
public static boolean opposite(OCell a, OCell b) {
if (a==b) return false;
if (!adjacent(a,b)) return false;
if (a.parent==b.parent) return false;
return a.parent.spaceId == b.parent.spaceId;
}
public OCell opposite() {
if (dim()>=spaceDim()) { return null; }
HashSet<OCell> candidates = cell.referrers;
for (OCell c:candidates) {
if (c==this) continue;
assert parent != null;
assert c.parent != null;
if (OCell.opposite(this,c))
return c;
}
return null;
}
public OCell snappedTo() {
if (outsnapped) {
return null;
}
return opposite();
}
@Override
public List<? extends BCell> facets() {
return cell.facets;
}
@Override
public Point normal() {
assert cell.normal().isNormal();
return cell.normal();
}
@Override
public ALocation location() {
return cell.location();
}
OCell(DCell dc, boolean proj3d) {
if (dc.location()._dst!=null) {
connectCell(dc.location()._dst);
}
else {
connectCell(new Cell());
dc.location._dst = cell;
cell.location = new Location(dc.location, proj3d);
for (DCell f : dc.facets()) {
OCell fcell = new OCell(f,proj3d);
fcell.connectParent(cell);
}
}
cell.spaceId = SpaceId.from(dc.space());
src = dc;
dc.dst = this;
}
void adjustSnapAfterDCopy() {
if (src.neighbor!=null) {
assert src.neighbor != null;
if (src.neighbor.dst==null) {}
else {
assert src.neighbor.dst != null;
assert cell.equals(src.neighbor.dst.cell) :
cell + "," + src.neighbor.dst.cell;
assert cell == src.neighbor.dst.cell ;
assert src.location.equals(src.neighbor.location);
assert src.location == src.neighbor.location;
assert src.parent.space().equals(src.neighbor.parent.space());
assert parent.spaceId == src.neighbor.dst.parent.spaceId :
"\n" + (new DSpace(parent.spaceId.dspace)) + "\n" + (new DSpace(src.neighbor.dst.parent.spaceId.dspace));
assert OCell.opposite(src.snappedTo().dst,this);
assert snappedTo() == src.snappedTo().dst : src.snappedTo() + "\n" + src.snappedTo().dst + "\n" + this;
}
}
else {
//src.snappedTo() == null
if ( snappedTo() != null ) {
//System.out.println("outsnapped adjusted after copy");
outsnapped = true;
opposite().outsnapped = true;
}
}
for (OCell f : cell.facets) {
f.adjustSnapAfterDCopy();
}
}
public void breakOpen() {
if (cell.isSplitted()) {
inner = new OCell(cell.inner,this);
outer = new OCell(cell.outer,this);
}
if (cell.isInner()) {
inner = this;
outer = null;
}
if (cell.isOuter()) {
inner = null;
outer = this;
}
splitCellIs = cell.splitCellIs;
}
public boolean checkSnap() {
if (isSplitted()) {
assert inner.checkSnap();
assert outer.checkSnap();
return true;
}
//not splitted
assert !cell().isSplitted() :
cell;
OCell snappedTo = snappedTo();
if (snappedTo != null) {
if (snappedTo.cell!=cell) {
// snappedTo.fixSnapAfterSplit();
}
assert snappedTo.cell == cell || snappedTo.snappedTo().isSplitted():
snappedTo.cell == cell || snappedTo.snappedTo().isSplitted();
assert snappedTo.cell == cell || snappedTo.isSplitted();
assert snappedTo.cell() == cell() || snappedTo.inner.cell == cell || snappedTo.outer.cell == cell;
if (snappedTo.snappedTo()!=this) {
snappedTo.outsnapped = false;
assert snappedTo.snappedTo() == this :
snappedTo.snappedTo();
snappedTo.outsnapped = true;
}
assert opposite().opposite() == this :
opposite().opposite();
assert snappedTo.snappedTo() == this :
snappedTo.snappedTo();
assert !snappedTo.isSplitted() :
snappedTo;
}
for ( OCell f : cell.facets ) {
assert f.checkSnap();
}
return true;
}
// private void snapTo(OCell _dst) {
// snappedTo = _dst;
// _dst.snappedTo = this;
// snappedToSet = true;
// snappedTo.snappedToSet = true;
// }
public void unsnap() {
outsnapped = true;
OCell snappedTo = opposite();
if (snappedTo!=null) {
snappedTo.outsnapped = true;
}
}
public boolean isOutSnapped() {
return outsnapped;
}
public void snapOut() {
unsnap();
for (OCell f:cell.facets) {
f.snapOut();
}
}
public boolean checkSnapCell() {
if (isSplitted()) {
assert inner.checkSnapCell();
assert outer.checkSnapCell();
return true;
}
if (!cell.isSplitted()) {
OCell snappedTo = snappedTo();
if (snappedTo!=null) {
assert snappedTo.cell() == cell();
assert snappedTo.snappedTo() == this :
snappedTo.snappedTo();
assert !snappedTo.isSplitted() :
snappedTo;
}
}
for ( OCell f : cell.facets ) {
assert f.checkSnapCell();
}
return true;
}
/* checks that each facets is contained in at most one parent
*/
@Override
public boolean checkFaces() {
for ( BCell f : facets() ) {
assert f.parent() != null;
//if (f.parent() == null) { f.parent = this; }
if ( f.parent() != cell ) {
assert false;
}
}
return true;
}
public int orientation() {
return orientation;
}
public HashSet<SpaceId> halfSpaces() {
return cell.halfSpaces();
}
public Iterator<OCell> iterator() {
return new Iterator<OCell>() {
public Vector<OCell> facets = cell.facets;
int pos = 0;
Iterator<OCell> fIt;
public boolean hasNext() {
while (pos<facets.size()) {
fIt = facets.get(pos).iterator();
if (fIt.hasNext()) { return true; }
pos = pos+1;
}
return false;
}
public OCell next() {
while (true) {
if(fIt.hasNext()) { return fIt.next(); }
pos = pos+1;
if (pos>=facets.size()) { break; }
fIt = facets.get(pos).iterator();
}
return null;
}
public void remove() {}
};
}
/**
* An OCell is internal if
* a) it's parent is internal
* b) it's parent is non-internal and its snappedTo something with non-internal parent
*/
boolean isInternal() {
if (parent()!=null && parent().isInternal()) return true;
//(has no parent or) is visible
OCell snappedTo = snappedTo();
if (snappedTo==null) return false;
if (snappedTo.parent().isInternal()) return false;
if (snappedTo.snappedTo()!=this) {
snappedTo.outsnapped = false;
assert snappedTo.snappedTo() == this :
snappedTo.snappedTo();
snappedTo.outsnapped = true;
}
assert snappedTo.snappedTo() == this :
snappedTo.snappedTo();
return true;
}
public void paint(D3Graphics g3, boolean woInternals) {
cell.paint(g3,woInternals);
if (!Main.debug.isSelected()) return;
if (dim()==2 && spaceDim() == 3) {
Point normal = normal();
normal.multiply(orientation);
Point3d a = cell.center3d();
Point3d b = cell.center3d();
b.add(normal.multiply(0.25));
g3.drawLine(a, b);
g3.drawBlob(b);
return;
}
}
}