package org.geogebra.common.geogebra3D.kernel3D.algos;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoConic3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3DLimited;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3DPart;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.kernelND.GeoConicND;
/**
* Algo for cylinder/cone from a conic and a height
*
* @author mathieu
*
*/
public abstract class AlgoQuadricLimitedConicHeight extends AlgoElement3D {
// input
private GeoConicND bottom;
private NumberValue height;
// output
private GeoQuadric3DPart side;
protected GeoConic3D top;
private GeoQuadric3DLimited quadric;
private AlgoQuadricSide algoSide;
private AlgoQuadricEndTop algoTop;
/**
*
* @param c
* construction
* @param labels
* labels
* @param bottom
* bottom side
* @param height
* height
* @param type
* type (cylinder/cone)
*/
public AlgoQuadricLimitedConicHeight(Construction c, String[] labels,
GeoConicND bottom, NumberValue height, int type) {
super(c);
this.bottom = bottom;
this.height = height;
quadric = new GeoQuadric3DLimited(c);
quadric.setType(type);
input = new GeoElement[] { bottom, (GeoElement) height };
((GeoElement) bottom).addAlgorithm(this);
((GeoElement) height).addAlgorithm(this);
// parent of output
quadric.setParentAlgorithm(this);
cons.addToAlgorithmList(this);
setQuadric();
algoSide = new AlgoQuadricSide(cons, quadric, true, bottom);
side = (GeoQuadric3DPart) algoSide.getQuadric();
side.setParentAlgorithm(this);
quadric.setSide(side);
createTop();
quadric.setBottomTop(bottom, top);
// output = new GeoElement[] {quadric,bottom,top,side};
setOutput();
quadric.initLabelsNoBottom(labels);
quadric.updatePartsVisualStyle();
if (height instanceof GeoNumeric) {
if (((GeoNumeric) height).isIndependent()) {
side.setChangeableCoordParent((GeoNumeric) height, bottom);
top.setChangeableCoordParent((GeoNumeric) height, bottom);
}
}
}
/**
* create the top side
*/
final protected void createTop() {
algoTop = new AlgoQuadricEndTop(cons, getQuadric());
top = algoTop.getSection();
top.setParentAlgorithm(this);
}
/**
* sets the output
*/
final protected void setOutput() {
setOutput(new GeoElement[] { getQuadric(), getQuadric().getTop(),
getQuadric().getSide() });
}
private void setQuadric() {
Coords o = bottom.getMidpoint3D();
// TODO cylinder with other conics (than circles)
double r = bottom.getHalfAxis(0);
double r2 = bottom.getHalfAxis(1);
double altitude = height.getDouble();
Coords d = bottom.getMainDirection().normalize();
Coords o2 = o.add(d.mul(altitude));
quadric.setDefined();
setQuadric(o, o2, d, bottom.getEigenvec3D(0), r, r2, 0, altitude);
}
@Override
public void compute() {
setQuadric();
// must compute side first for midpoint
algoSide.compute();
algoTop.compute();
quadric.calcVolume();
}
abstract protected void setQuadric(Coords o1, Coords o2, Coords d,
Coords eigen, double r, double r2, double min, double max);
public GeoQuadric3DLimited getQuadric() {
return quadric;
}
// @Override
// public void update() {
//
// if (stopUpdateCascade) {
// return;
// }
//
// compute();
// quadric.update();
//
// if (!getQuadric().isLabelSet()) { // geo is in sequence/list : update
// // top and side
// getQuadric().getTop().getParentAlgorithm().update();
// getQuadric().getSide().getParentAlgorithm().update();
// }
//
// }
@Override
protected void getOutputXML(StringBuilder sb) {
super.getOutputXML(sb);
// append XML for bottom once more, to avoid override of specific
// properties
if (bottom.isLabelSet()) {
bottom.getXML(false, sb);
}
}
// /////////////////////////////////////////////////////
// FOR PREVIEWABLE
// /////////////////////////////////////////////////////
public void setOutputPointsEuclidianVisible(boolean b) {
//
}
public void notifyUpdateOutputPoints() {
//
}
public GeoElement getTopFace() {
return top;
}
public GeoConicND getBottomFace() {
return bottom;
}
public void setOutputOtherEuclidianVisible(boolean b) {
side.setEuclidianVisible(b);
top.setEuclidianVisible(b);
}
public void notifyUpdateOutputOther() {
getKernel().notifyUpdate(side);
getKernel().notifyUpdate(top);
}
}