package org.geogebra.common.geogebra3D.kernel3D.geos;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoLinePoint;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.PathMover;
import org.geogebra.common.kernel.PathMoverGeneric;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.arithmetic.ValueType;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoLineND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoVectorND;
import org.geogebra.common.plugin.GeoClass;
import org.geogebra.common.util.ExtendedBoolean;
import org.geogebra.common.util.lang.Unicode;
/**
* 3D line
*/
public class GeoLine3D extends GeoCoordSys1D {
private String parameter = Unicode.lambda + "";
/**
* creates a line joining O and I
*
* @param c
* construction
* @param O
* start point
* @param I
* end point
*/
public GeoLine3D(Construction c, GeoPointND O, GeoPointND I) {
super(c, O, I);
}
/**
* @param c
* construction
*/
public GeoLine3D(Construction c) {
this(c, false);
}
/**
* @param c
* construction
* @param isIntersection
* flag for intersection lines
*/
public GeoLine3D(Construction c, boolean isIntersection) {
super(c, isIntersection);
}
/**
* @param c
* construction
* @param o
* start point
* @param v
* diection
*/
public GeoLine3D(Construction c, Coords o, Coords v) {
super(c, o, v);
}
@Override
public void setToParametric(String s) {
this.parameter = s;
}
@Override
public final void setStartPoint(GeoPointND P) {
startPoint = P;
}
@Override
protected GeoCoordSys1D create(Construction cons1) {
return new GeoLine3D(cons1);
}
@Override
public GeoClass getGeoClassType() {
return GeoClass.LINE3D;
}
@Override
public boolean isEqual(GeoElementND geo) {
if (geo instanceof GeoLineND) {
Coords diff = ((GeoLineND) geo).getDirectionInD3()
.crossProduct(getDirectionInD3().normalize());
return diff.isZero() && getCoordSys().getOrigin()
.sub(((GeoLineND) geo).getOrigin())
.crossProduct(getDirectionInD3()).isZero();
}
return false;
}
private boolean showUndefinedInAlgebraView = false;
/**
* Set whether this line should be visible in AV when undefined
*
* @param flag
* true to show undefined
*/
public void showUndefinedInAlgebraView(boolean flag) {
showUndefinedInAlgebraView = flag;
}
@Override
public boolean showInAlgebraView() {
return isDefined() || showUndefinedInAlgebraView;
}
@Override
protected boolean showInEuclidianView() {
return coordsys.isDefined();
}
@Override
public String toValueString(StringTemplate tpl) {
return buildValueString(tpl).toString();
}
@Override
final public String toString(StringTemplate tpl) {
StringBuilder sbToString = getSbToString();
sbToString.setLength(0);
sbToString.append(label);
sbToString.append(": "); // TODO use kernel property
sbToString.append(buildValueString(tpl));
return sbToString.toString();
}
private StringBuilder buildValueString(StringTemplate tpl) {
StringBuilder sbToString = getSbBuildValueString();
if (!isDefined()) {
sbToString.append("X = (?, ?, ?)");
return sbToString;
}
AlgoElement algo = getParentAlgorithm();
if (algo instanceof AlgoLinePoint) {
AlgoLinePoint algoLP = (AlgoLinePoint) algo;
GeoElement[] geos = algoLP.getInput();
if (geos[0].isGeoPoint() && geos[1].isGeoVector()) {
// use original coordinates for displaying, not normalized form
// for Line[ A, u ]
GeoPointND pt = (GeoPointND) geos[0];
Coords coords1 = pt.getInhomCoordsInD3();
GeoVectorND vec = (GeoVectorND) geos[1];
Coords coords2 = vec.getCoordsInD3();
sbToString.append("X = (");
sbToString.append(kernel.format(coords1.getX(), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(coords1.getY(), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(coords1.getZ(), tpl));
sbToString.append(") + ");
sbToString.append(parameter);
sbToString.append(" (");
sbToString.append(kernel.format(coords2.getX(), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(coords2.getY(), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(coords2.getZ(), tpl));
sbToString.append(")");
return sbToString;
}
}
Coords O = coordsys.getOrigin();// TODO inhom coords
Coords V = coordsys.getVx();
sbToString.append("X = (");
sbToString.append(kernel.format(O.get(1), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(O.get(2), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(O.get(3), tpl));
sbToString.append(") + ");
sbToString.append(parameter);
sbToString.append(" (");
sbToString.append(kernel.format(V.get(1), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(V.get(2), tpl));
sbToString.append(", ");
sbToString.append(kernel.format(V.get(3), tpl));
sbToString.append(")");
return sbToString;
}
@Override
protected void getXMLtags(StringBuilder sb) {
super.getXMLtags(sb);
getCoordsXML(sb);
sb.append("\t<eqnStyle style=\"parametric\" parameter=\"");
sb.append(parameter);
sb.append("\"/>\n");
}
/**
* set coords for XML
*
* @param sb
* string for XML
*/
protected void getCoordsXML(StringBuilder sb) {
Coords o = coordsys.getOrigin();// TODO inhom coords
Coords v = coordsys.getVx();
sb.append("\t<coords");
sb.append(" ox=\"");
sb.append(o.getX());
sb.append("\" oy=\"");
sb.append(o.getY());
sb.append("\" oz=\"");
sb.append(o.getZ());
sb.append("\" ow=\"");
sb.append(o.getW());
sb.append("\" vx=\"");
sb.append(v.getX());
sb.append("\" vy=\"");
sb.append(v.getY());
sb.append("\" vz=\"");
sb.append(v.getZ());
sb.append("\" vw=\"");
sb.append(v.getW());
sb.append("\"/>\n");
}
@Override
final public boolean isGeoLine() {
return true;
}
// Path3D interface
@Override
public PathMover createPathMover() {
return new PathMoverGeneric(this);
}
@Override
public double getMaxParameter() {
return Double.POSITIVE_INFINITY;
}
@Override
public double getMinParameter() {
return Double.NEGATIVE_INFINITY;
}
@Override
public boolean isClosedPath() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isValidCoord(double x) {
return true;
}
@Override
public final void removePointOnLine(GeoPointND p) {
// TODO
}
@Override
public boolean respectLimitedPath(double param) {
return true;
}
@Override
public GeoPointND setStandardStartPoint() {
// TODO Auto-generated method stub
return startPoint;
}
/*
* //////////////////// // ROTATE ////////////////////
*
*
*
*
* public void rotate(NumberValue phiValue) {
*
* Coords o = getCoordSys().getOrigin();
*
* double z = o.getZ(); if (!Kernel.isZero(z)){ setUndefined(); return; }
*
* Coords v = getCoordSys().getVx();
*
* double vz = v.getZ(); if (!Kernel.isZero(vz)){ setUndefined(); return; }
*
* double phi = phiValue.getDouble(); double cos = Math.cos(phi); double sin
* = Math.sin(phi);
*
* double x = o.getX(); double y = o.getY(); double w = o.getW();
*
*
* Coords oRot = new Coords(x * cos - y * sin, x * sin + y * cos, z, w);
*
* double vx = v.getX(); double vy = v.getY(); double vw = v.getW();
*
*
* Coords vRot = new Coords(vx * cos - vy * sin, vx * sin + vy * cos, vz,
* vw);
*
* setCoord(oRot, vRot);
*
* }
*
* final public void rotate(NumberValue phiValue, GeoPoint Q) {
*
* Coords o = getCoordSys().getOrigin();
*
* double z = o.getZ(); if (!Kernel.isZero(z)){ setUndefined(); return; }
*
* Coords v = getCoordSys().getVx();
*
* double vz = v.getZ(); if (!Kernel.isZero(vz)){ setUndefined(); return; }
*
* double phi = phiValue.getDouble(); double cos = Math.cos(phi); double sin
* = Math.sin(phi);
*
* double x = o.getX(); double y = o.getY(); double w = o.getW();
*
* double qx = w * Q.getInhomX(); double qy = w * Q.getInhomY();
*
* Coords oRot = new Coords((x - qx) * cos + (qy - y) * sin + qx, (x - qx) *
* sin + (y - qy) * cos + qy, z, w);
*
* double vx = v.getX(); double vy = v.getY(); double vw = v.getW();
*
*
* Coords vRot = new Coords(vx * cos - vy * sin, vx * sin + vy * cos, vz,
* vw);
*
* setCoord(oRot, vRot);
*
*
* }
*
* final private void rotate(NumberValue phiValue, Coords o1, Coords vn) {
*
* if (vn.isZero()){ setUndefined(); return; } Coords vn2 = vn.normalized();
*
*
* Coords point = getCoordSys().getOrigin(); Coords s =
* point.projectLine(o1, vn)[0]; //point projected on the axis
*
* Coords v1 = point.sub(s); //axis->point of the line
*
*
* Coords v = getCoordSys().getVx(); //direction of the line
*
*
* double phi = phiValue.getDouble(); double cos = Math.cos(phi); double sin
* = Math.sin(phi);
*
* // new line origin Coords v2 = vn2.crossProduct4(v1); Coords oRot =
* s.add(v1.mul(cos)).add(v2.mul(sin));
*
* // new line direction v2 = vn2.crossProduct4(v); v1 =
* v2.crossProduct4(vn2); Coords vRot =
* v1.mul(cos).add(v2.mul(sin)).add(vn2.mul(v.dotproduct(vn2)));
*
*
* setCoord(oRot, vRot); }
*
*
*
* public void rotate(NumberValue phiValue, GeoPointND S, GeoDirectionND
* orientation) {
*
* Coords o1 = S.getInhomCoordsInD3();
*
* Coords vn = orientation.getDirectionInD3();
*
* rotate(phiValue, o1, vn); }
*
* public void rotate(NumberValue phiValue, GeoLineND line) {
*
* Coords o1 = line.getStartInhomCoords(); Coords vn =
* line.getDirectionInD3();
*
*
* rotate(phiValue, o1, vn);
*
* }
*/
@Override
final public HitType getLastHitType() {
return HitType.ON_BOUNDARY;
}
@Override
public boolean isParametric() {
return true;
}
@Override
public ValueType getValueType() {
return ValueType.PARAMETRIC3D;
}
@Override
public ExtendedBoolean isCongruent(GeoElement geo) {
return ExtendedBoolean.newExtendedBoolean(geo.isGeoLine());
}
@Override
public double distance(GeoPointND pt) {
return super.distance(pt);
}
@Override
public Coords getOrigin() {
return getCoordSys().getOrigin();
}
}