package org.geogebra.common.geogebra3D.kernel3D.implicit3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoIntersect3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoRoots;
import org.geogebra.common.kernel.algos.GetCommand;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.Function;
import org.geogebra.common.kernel.arithmetic.FunctionNVar;
import org.geogebra.common.kernel.arithmetic.FunctionVariable;
import org.geogebra.common.kernel.arithmetic.MyDouble;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoImplicitSurfaceND;
import org.geogebra.common.kernel.kernelND.GeoLineND;
import org.geogebra.common.plugin.Operation;
/**
* Find intersection between implicit surface and line
*
* @author GSoCImplicit2015
*
*/
public class AlgoIntersectImplicitSurface extends AlgoIntersect3D {
private static final int SAMPLE_SIZE = 100;
private GeoImplicitSurfaceND surface;
private GeoElementND eqn;
private OutputHandler<GeoPoint3D> outputs;
private String labels[];
/**
*
* @param c
* construction
* @param surface
* implicit surface
* @param labels
* labels
* @param equation
* equation
*/
public AlgoIntersectImplicitSurface(Construction c, String[] labels,
GeoImplicitSurfaceND surface, GeoElementND equation) {
super(c);
this.surface = surface;
this.eqn = equation;
this.labels = labels;
initForNearToRelationship();
setInputOutput();
compute();
}
@Override
public GeoPoint3D[] getIntersectionPoints() {
return outputs.getOutput(new GeoPoint3D[outputs.size()]);
}
@Override
protected GeoPoint3D[] getLastDefinedIntersectionPoints() {
return getIntersectionPoints();
}
@Override
public void compute() {
if (surface == null || !surface.isDefined()) {
outputs.adjustOutputSize(0);
return;
}
if (eqn instanceof GeoLineND) {
intersectLine((GeoLineND) eqn);
}
}
private void intersectLine(GeoLineND eq) {
Coords v = eq.getDirectionInD3();
Coords r = eq.getStartPoint().getCoordsInD3();
FunctionVariable t = new FunctionVariable(kernel, "x");
ExpressionNode x = new ExpressionNode(kernel, r.getX());
ExpressionNode y = new ExpressionNode(kernel, r.getY());
ExpressionNode z = new ExpressionNode(kernel, r.getZ());
x = x.plus(new ExpressionNode(kernel, t, Operation.MULTIPLY,
new MyDouble(kernel, v.getX())));
y = y.plus(new ExpressionNode(kernel, t, Operation.MULTIPLY,
new MyDouble(kernel, v.getY())));
z = z.plus(new ExpressionNode(kernel, t, Operation.MULTIPLY,
new MyDouble(kernel, v.getZ())));
intersectParameteric(x, y, z);
}
private void intersectParameteric(ExpressionNode x, ExpressionNode y,
ExpressionNode z) {
FunctionNVar func = surface.getExpression();
FunctionVariable[] vars = func.getFunctionVariables();
ExpressionNode exp = func.getExpression().getCopy(getKernel());
exp.replace(vars[0], x);
exp.replace(vars[1], y);
if (vars.length == 3) {
exp.replace(vars[2], z);
}
exp.simplifyConstantIntegers();
Function fn = new Function(exp);
double[] roots = AlgoRoots.findRoots(new GeoFunction(cons, fn),
kernel.getViewsXMin(surface), kernel.getViewsYMax(surface),
SAMPLE_SIZE);
if (roots == null || roots.length == 0) {
outputs.adjustOutputSize(0);
return;
}
Function f1 = new Function(x);
Function f2 = new Function(y);
Function f3 = new Function(z);
f1.initFunction();
f2.initFunction();
f3.initFunction();
outputs.adjustOutputSize(roots.length);
for (int i = 0; i < roots.length; i++) {
double vx = f1.value(roots[i]);
double vy = f2.value(roots[i]);
double vz = f3.value(roots[i]);
outputs.getElement(i).setCoords(vx, vy, vz, 1.0);
}
}
@Override
public void initForNearToRelationship() {
// TODO Ask, what is it?
}
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = surface.toGeoElement();
input[1] = eqn.toGeoElement();
outputs = new OutputHandler<GeoPoint3D>(
new elementFactory<GeoPoint3D>() {
@Override
public GeoPoint3D newElement() {
GeoPoint3D p = new GeoPoint3D(cons);
p.setParentAlgorithm(AlgoIntersectImplicitSurface.this);
return p;
}
});
setDependencies();
}
/**
*
* @param labels
* set labels
*/
public void setLabels(String[] labels) {
this.labels = labels;
outputs.setLabels(this.labels);
update();
}
@Override
public GetCommand getClassName() {
return Commands.Intersect;
}
}