package org.geogebra.common.geogebra3D.kernel3D.implicit3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPlane3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.Matrix.CoordSys;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.arithmetic.FunctionNVar;
import org.geogebra.common.kernel.implicit.GeoImplicit;
import org.geogebra.common.kernel.implicit.GeoImplicitCurve;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
/**
* 3D extension of implicit curves
*
*/
public class GeoImplicitCurve3D extends GeoImplicitCurve {
private CoordSys transformCoordSys;
private FunctionNVar functionExpression;
/**
* @param c
* construction
*/
public GeoImplicitCurve3D(Construction c) {
super(c);
this.transformCoordSys = new CoordSys(2);
transformCoordSys.set(CoordSys.XOY);
}
/**
* Copy constructor
*
* @param geo
* curve to copy
*/
public GeoImplicitCurve3D(GeoImplicitCurve geo) {
this(geo.getConstruction());
set(geo);
}
@Override
public CoordSys getTransformedCoordSys() {
return transformCoordSys;
}
/**
* @param sys
* transformed system
*/
public void setTransformedCoordSys(CoordSys sys) {
transformCoordSys.set(sys);
}
@Override
public void set(GeoElementND geo) {
super.set(geo);
GeoImplicit implicit = (GeoImplicit) geo;
transformCoordSys.set(implicit.getTransformedCoordSys());
setFunctionExpression(implicit.getFunctionDefinition());
setPlaneEquation(implicit.getPlaneEquation());
translateZ = implicit.getTranslateZ();
}
@Override
public GeoImplicitCurve3D copy() {
GeoImplicitCurve3D curve = new GeoImplicitCurve3D(cons);
curve.set(this);
return curve;
}
private double[] planeEquationNumbers;
private static final String[] VAR_STRING = { "x", "y" };
@Override
public String toValueString(StringTemplate tpl) {
StringBuilder valueSb = new StringBuilder(50);
valueSb.append("(");
if (functionExpression != null) {
valueSb.append(
functionExpression.getExpression().toValueString(tpl));
valueSb.append(" = ");
if (Kernel.isEpsilon(planeEquation.getZ(), planeEquation.getY(),
planeEquation.getX())) {
// can't replace z by plane equation
valueSb.append("z");
kernel.appendConstant(valueSb, -translateZ, tpl);
} else {
// replace z by plane equation
if (planeEquationNumbers == null) {
planeEquationNumbers = new double[3];
}
planeEquationNumbers[0] = -planeEquation.getX()
/ planeEquation.getZ();
planeEquationNumbers[1] = -planeEquation.getY()
/ planeEquation.getZ();
planeEquationNumbers[2] = -planeEquation.getW()
/ planeEquation.getZ() - translateZ;
valueSb.append(kernel.buildLHS(planeEquationNumbers, VAR_STRING,
true, false, false, true, tpl));
}
} else {
valueSb.append(getExpression().toValueString(tpl));
valueSb.append(" = 0");
}
valueSb.append(",");
valueSb.append(
GeoPlane3D.buildValueString(tpl, kernel, planeEquation, false));
valueSb.append(")");
return valueSb.toString();
}
@Override
public boolean isGeoElement3D() {
return true;
}
private Coords tmpCoords = new Coords(4);
private Coords tmpCoords3d = new Coords(4);
@Override
protected void locusPointChanged(GeoPointND PI) {
Coords willingCoords = null, willingDirection = null;
GeoPoint3D p3d = (GeoPoint3D) PI;
if (p3d.hasWillingCoords()) {
willingCoords = p3d.getWillingCoords();
} else {
willingCoords = PI.getInhomCoordsInD3();
}
if (p3d.hasWillingDirection()) {
willingDirection = p3d.getWillingDirection();
} else {
willingDirection = transformCoordSys.getVz();
}
willingCoords.projectPlaneInPlaneCoords(transformCoordSys.getVx(),
transformCoordSys.getVy(), willingDirection,
transformCoordSys.getOrigin(), tmpCoords);
locus.pointChanged(tmpCoords, PI.getPathParameter());
transformCoordSys.getPointFromOriginVectors(tmpCoords, tmpCoords3d);
PI.setCoords(tmpCoords3d, false);
p3d.setWillingCoordsUndefined();
p3d.setWillingDirectionUndefined();
}
@Override
protected void locusPathChanged(GeoPointND PI) {
PI.getInhomCoordsInD3().projectPlaneInPlaneCoords(
transformCoordSys.getVx(), transformCoordSys.getVy(),
transformCoordSys.getVz(), transformCoordSys.getOrigin(),
tmpCoords);
locus.pathChanged(tmpCoords, PI.getPathParameter());
transformCoordSys.getPointFromOriginVectors(tmpCoords, tmpCoords3d);
PI.setCoords(tmpCoords3d, false);
}
@Override
public void translate(Coords v) {
transformCoordSys.translate(v);
transformCoordSys.translateEquationVector(v);
functionExpression.translate(v);
translateZ += v.getZ();
CoordSys.translateEquationVector(planeEquation, v);
euclidianViewUpdate();
}
/**
* @param expression
* defining expression
*/
public void setFunctionExpression(FunctionNVar expression) {
this.functionExpression = expression.deepCopy(kernel);
}
@Override
public FunctionNVar getFunctionDefinition() {
return functionExpression;
}
private Coords planeEquation = new Coords(4);
/**
* @param planeEquation
* normal vector of the plane
*/
public void setPlaneEquation(Coords planeEquation) {
this.planeEquation.set(planeEquation);
}
@Override
public Coords getPlaneEquation() {
return this.planeEquation;
}
private double translateZ = 0;
@Override
public double getTranslateZ() {
return translateZ;
}
}