package org.geogebra.common.geogebra3D.kernel3D.algos;
import java.util.ArrayList;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPolygon3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPolyhedron;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoSegment3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.kernelND.GeoSegmentND;
/**
* @author ggb3D
*
* Creates a new GeoPolyhedron
*
*/
public abstract class AlgoPolyhedron extends AlgoElement3D {
/** points generated as output */
protected OutputHandler<GeoPoint3D> outputPoints;
/** output handler */
protected OutputHandler<GeoPolyhedron> outputPolyhedron;
/** output polyhedron */
protected GeoPolyhedron polyhedron;
// ///////////////////////////////////////////
// POLYHEDRON OF DETERMINED TYPE
// //////////////////////////////////////////
/**
* @param c
* construction
*/
protected AlgoPolyhedron(Construction c) {
super(c);
cons.addToAlgorithmList(this);
outputPolyhedron = new OutputHandler<GeoPolyhedron>(
new elementFactory<GeoPolyhedron>() {
@Override
public GeoPolyhedron newElement() {
GeoPolyhedron p = new GeoPolyhedron(cons);
p.setParentAlgorithm(AlgoPolyhedron.this);
return p;
}
});
outputPolyhedron.adjustOutputSize(1);
polyhedron = getPolyhedron();
outputPoints = createOutputPointsHandler();
createOutputPolygons();
createOutputSegments();
}
/**
*
* @return true if no input point or if first input point is visible
*/
abstract protected boolean isFirstInputPointVisible();
/**
*
* @return true if no input point or if first input point has label visible
*/
abstract protected boolean isFirstInputPointLabelVisible();
/**
* create the faces of the polyhedron
*/
protected void createFaces() {
polyhedron.createFaces();
}
/**
* create the output segments handlers
*/
abstract protected void createOutputSegments();
/**
* @return an output handler for segments
*/
protected OutputHandler<GeoSegment3D> createOutputSegmentsHandler() {
return new OutputHandler<GeoSegment3D>(
new elementFactory<GeoSegment3D>() {
@Override
public GeoSegment3D newElement() {
GeoSegment3D s = new GeoSegment3D(cons);
// s.setParentAlgorithm(AlgoPolyhedron.this);
return s;
}
});
}
/**
* create the output polygons handlers
*/
abstract protected void createOutputPolygons();
/**
* @return an output handler for polygons
*/
protected OutputHandler<GeoPolygon3D> createOutputPolygonsHandler() {
return new OutputHandler<GeoPolygon3D>(
new elementFactory<GeoPolygon3D>() {
@Override
public GeoPolygon3D newElement() {
GeoPolygon3D p = new GeoPolygon3D(cons);
// p.setParentAlgorithm(AlgoPolyhedron.this);
return p;
}
});
}
/**
* Add this to dependency set of all inputs
*/
protected void addAlgoToInput() {
for (int i = 0; i < input.length; i++) {
input[i].addAlgorithm(this);
}
}
/**
* Update output dependencies
*/
abstract protected void updateOutput();
/**
* Alias for updateOutput TODO only use one
*/
protected final void setOutput() {
updateOutput();
// cons.addToAlgorithmList(this);
}
/**
* @return the polyhedron
*/
public GeoPolyhedron getPolyhedron() {
return outputPolyhedron.getElement(0);
}
@Override
public void removeOutputExcept(GeoElement keepGeo) {
for (int i = 0; i < super.getOutputLength(); i++) {
GeoElement geo = super.getOutput(i);
if (geo != keepGeo) {
if (geo.isGeoPoint()) {
removePoint(geo);
} else {
geo.doRemove();
}
}
}
}
private void removePoint(GeoElement oldPoint) {
// remove dependent algorithms (e.g. segments) from update sets of
// objects further up (e.g. polygon) the tree
ArrayList<AlgoElement> algoList = oldPoint.getAlgorithmList();
for (int k = 0; k < algoList.size(); k++) {
AlgoElement algo = algoList.get(k);
for (int j = 0; j < input.length; j++) {
input[j].removeFromUpdateSets(algo);
}
}
// remove old point
oldPoint.setParentAlgorithm(null);
// remove dependent segment algorithm that are part of this polygon
// to make sure we don't remove the polygon as well
GeoPolyhedron poly = getPolyhedron();
for (int k = 0; k < algoList.size(); k++) {
AlgoElement algo = algoList.get(k);
// make sure we don't remove the polygon as well
if (algo instanceof AlgoJoinPoints3D
&& ((AlgoJoinPoints3D) algo).getPoly() == poly) {
continue;
} else if (algo instanceof AlgoPolygon3D
&& ((AlgoPolygon3D) algo).getPolyhedron() == poly) {
continue;
}
algo.remove();
}
algoList.clear();
// remove point
oldPoint.doRemove();
}
@Override
protected void updateDependentGeos() {
getPolyhedron().update();
}
/**
* @return an output handler for points
*/
protected OutputHandler<GeoPoint3D> createOutputPointsHandler() {
return new OutputHandler<GeoPoint3D>(new PointFactory());
}
/**
* Creates 3D points, sets visibility flags
*
*/
protected class PointFactory implements elementFactory<GeoPoint3D> {
@Override
public GeoPoint3D newElement() {
GeoPoint3D p = new GeoPoint3D(cons);
p.setCoords(0, 0, 0, 1);
p.setParentAlgorithm(AlgoPolyhedron.this);
boolean visible = false;
boolean labelVisible = false;
int size = outputPoints.size();
if (size > 0) { // check if at least one element is
// visible
for (int i = 0; i < size && !visible && !labelVisible; i++) {
visible = visible
|| outputPoints.getElement(i).isEuclidianVisible();
labelVisible = labelVisible
|| outputPoints.getElement(i).getLabelVisible();
}
} else { // no element yet
visible = isFirstInputPointVisible();
labelVisible = isFirstInputPointLabelVisible();
}
p.setEuclidianVisible(visible);
if (!visible) { // if not visible, we don't want
// setParentAlgorithm() to change it
p.dontSetEuclidianVisibleBySetParentAlgorithm();
}
p.setLabelVisible(labelVisible);
if (getPolyhedron().getShowObjectCondition() != null) {
try {
p.setShowObjectCondition(
getPolyhedron().getShowObjectCondition());
} catch (Exception e) {
// circular definition
}
}
getPolyhedron().addPointCreated(p);
return p;
}
}
@Override
protected void getOutputXML(StringBuilder sb){
super.getOutputXML(sb);
//append XML for polygon and segments linked once more, to avoid override of specific properties
for (GeoPolygon polygon : polyhedron.getPolygonsLinked()) {
polygon.getXML(false, sb);
}
for (GeoSegmentND segment : polyhedron.getSegmentsLinked()){
if (segment.isLabelSet()){
((GeoElement) segment).getXML(false, sb);
}
}
}
}