package org.geogebra.common.geogebra3D.euclidianFor3D;
import org.geogebra.common.euclidian.EuclidianController;
import org.geogebra.common.euclidian.EuclidianControllerCompanion;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoJoinPoints3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoMidpoint3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoPolarLine3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.geos.GeoAngle;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.kernelND.GeoConicND;
import org.geogebra.common.kernel.kernelND.GeoDirectionND;
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.GeoSegmentND;
import org.geogebra.common.kernel.kernelND.GeoVectorND;
import org.geogebra.common.plugin.GeoClass;
public class EuclidianControllerFor3DCompanion
extends EuclidianControllerCompanion {
public EuclidianControllerFor3DCompanion(EuclidianController ec) {
super(ec);
}
@Override
protected GeoAngle createAngle(GeoPointND A, GeoPointND B, GeoPointND C) {
GeoDirectionND orientation = ec.getView().getDirection();
if (((GeoElement) A).isGeoElement3D()
|| ((GeoElement) B).isGeoElement3D()
|| ((GeoElement) C).isGeoElement3D()) { // at least one 3D geo
if (orientation == ec.kernel.getSpace()) { // space is default
// orientation for 3D
// objects
return ec.kernel.getManager3D().Angle3D(null, A, B, C);
}
return ec.kernel.getManager3D().Angle3D(null, A, B, C, orientation); // use
// view
// orientation
}
// 2D geos
if (orientation == ec.kernel.getXOYPlane()) { // xOy plane is default
// orientation for 2D
// objects
return super.createAngle(A, B, C);
}
return ec.kernel.getManager3D().Angle3D(null, A, B, C, orientation); // use
// view
// orientation
}
@Override
protected GeoElement[] createAngles(GeoPolygon p) {
GeoDirectionND orientation = ec.getView().getDirection();
if (p.isGeoElement3D()) { // 3D polygon
if (orientation == ec.kernel.getSpace()) { // space is default
// orientation for 3D
// objects
return ec.kernel.getManager3D().Angles3D(null, p);
}
return ec.kernel.getManager3D().Angles3D(null, p, orientation); // use
// view
// orientation
}
// 2D polygon
if (orientation == ec.kernel.getXOYPlane()) { // xOy plane is default
// orientation for 2D
// objects
return super.createAngles(p);
}
return ec.kernel.getManager3D().Angles3D(null, p, orientation); // use
// view
// orientation
}
@Override
protected GeoAngle createAngle(GeoVectorND v1, GeoVectorND v2) {
GeoDirectionND orientation = ec.getView().getDirection();
if (v1.isGeoElement3D() || v2.isGeoElement3D()) { // at least one 3D geo
if (orientation == ec.kernel.getSpace()) { // space is default
// orientation for 3D
// objects
return ec.kernel.getManager3D().Angle3D(null, v1, v2);
}
return ec.kernel.getManager3D().Angle3D(null, v1, v2, orientation); // use
// view
// orientation
}
// 2D polygon
if (orientation == ec.kernel.getXOYPlane()) { // xOy plane is default
// orientation for 2D
// objects
return super.createAngle(v1, v2);
}
return ec.kernel.getManager3D().Angle3D(null, v1, v2, orientation); // use
// view
// orientation
}
@Override
public GeoAngle createAngle(GeoPointND p1, GeoPointND p2, GeoNumberValue a,
boolean clockWise) {
GeoDirectionND direction = ec.getView().getDirection();
if (direction == ec.kernel.getXOYPlane()
|| direction == ec.kernel.getSpace()) { // use xOy plane
if (p1.isGeoElement3D() || p2.isGeoElement3D()) {
return (GeoAngle) ec.kernel.getManager3D().Angle(null, p1, p2,
a, ec.kernel.getXOYPlane(), !clockWise)[0];
}
return super.createAngle(p1, p2, a, clockWise);
}
return (GeoAngle) ec.kernel.getManager3D().Angle(null, p1, p2, a,
direction, !clockWise)[0];
}
@Override
protected GeoAngle createLineAngle(GeoLineND g, GeoLineND h) {
GeoDirectionND orientation = ec.getView().getDirection();
if (g.isGeoElement3D() || h.isGeoElement3D()) { // at least one 3D geo
if (orientation == ec.kernel.getSpace()) { // space is default
// orientation for 3D
// objects
return ec.kernel.getManager3D().createLineAngle(g, h);
}
return ec.kernel.getManager3D().createLineAngle(g, h, orientation); // use
// view
// orientation
}
// 2D geos
if (orientation == ec.kernel.getXOYPlane()) { // xOy plane is default
// orientation for 2D
// objects
return super.createLineAngle(g, h);
}
return ec.kernel.getManager3D().createLineAngle(g, h, orientation); // use
// view
// orientation
}
@Override
protected GeoElement[] translate(GeoElement geo, GeoVectorND vec) {
if (geo.isGeoElement3D() || ((GeoElement) vec).isGeoElement3D()) {
return ec.kernel.getManager3D().Translate3D(null, geo, vec);
}
return super.translate(geo, vec);
}
@Override
protected GeoElement[] mirrorAtPoint(GeoElement geo, GeoPointND point) {
if (geo.isGeoElement3D() || ((GeoElement) point).isGeoElement3D()) {
return ec.kernel.getManager3D().Mirror3D(null, geo, point);
}
return super.mirrorAtPoint(geo, point);
}
@Override
protected GeoElement[] mirrorAtLine(GeoElement geo, GeoLineND line) {
if (geo.isGeoElement3D() || ((GeoElement) line).isGeoElement3D()) {
return ec.kernel.getManager3D().Mirror3D(null, geo, line);
}
return super.mirrorAtLine(geo, line);
}
@Override
public GeoElement[] dilateFromPoint(GeoElement geo, GeoNumberValue num,
GeoPointND point) {
if (geo.isGeoElement3D() || ((GeoElement) point).isGeoElement3D()) {
return ec.kernel.getManager3D().Dilate3D(null, geo, num, point);
}
return super.dilateFromPoint(geo, num, point);
}
/**
* Method used when geos are both 2D
*
* @param a
* first geo
* @param b
* second geo
* @return single intersection point
*/
public GeoPointND getSingleIntersectionPointFrom2D(GeoElement a,
GeoElement b, boolean coords2D) {
return super.getSingleIntersectionPoint(a, b, coords2D);
}
@Override
public GeoPointND getSingleIntersectionPoint(GeoElement a, GeoElement b,
boolean coords2D) {
// check if a and b are two 2D geos
if (!a.isGeoElement3D() && !b.isGeoElement3D()) {
return getSingleIntersectionPointFrom2D(a, b, coords2D);
}
GeoPointND point = null;
// first hit is a line
if (a.isGeoLine()) {
if (b.isGeoLine()) {
/*
* if (!((GeoLine) a).linDep((GeoLine) b)) { return ec.kernel
* .IntersectLines(null, (GeoLine) a, (GeoLine) b); }
*/
point = (GeoPoint3D) ec.kernel.getManager3D().Intersect(null,
(GeoLineND) a, (GeoLineND) b);
} else if (b.isGeoConic()) {
point = ec.kernel.getManager3D().IntersectLineConicSingle(null,
(GeoLineND) a, (GeoConicND) b, ec.xRW, ec.yRW,
ec.getView().getInverseMatrix());
/*
* } else if (b.isGeoFunctionable()) { // line and function
* GeoFunction f = ((GeoFunctionable) b).getGeoFunction(); if
* (f.isPolynomialFunction(false)) { return
* ec.kernel.IntersectPolynomialLineSingle(null, f, (GeoLine) a,
* xRW, yRW); } GeoPoint2 initPoint = new GeoPoint2(
* ec.kernel.getConstruction()); initPoint.setCoords(xRW, yRW,
* 1.0); return ec.kernel.IntersectFunctionLine(null, f,
* (GeoLine) a, initPoint);
*/
} else {
return null;
}
}
// first hit is a conic
else if (a.isGeoConic()) {
if (b.isGeoLine()) {
point = ec.kernel.getManager3D().IntersectLineConicSingle(null,
(GeoLineND) b, (GeoConicND) a, ec.xRW, ec.yRW,
ec.getView().getInverseMatrix());
} else if (b.isGeoConic() && !a.isEqual(b)) {
point = ec.kernel.getManager3D().IntersectConicsSingle(null,
(GeoConicND) a, (GeoConicND) b, ec.xRW, ec.yRW,
ec.getView().getInverseMatrix());
} else {
return null;
}
}
if (point != null) {
if (coords2D) {
point.setCartesian();
} else {
point.setCartesian3D();
}
point.update();
}
return point;
}
@Override
protected GeoElement[] orthogonal(GeoPointND point, GeoLineND line) {
return new GeoElement[] { (GeoElement) ec.kernel.getManager3D()
.OrthogonalLine3D(null, point, line,
ec.getView().getDirection()) };
}
@Override
public GeoPointND createNewPoint(String label, boolean forPreviewable,
Path path, double x, double y, double z, boolean complex,
boolean coords2D) {
// check if the path is 3D geo or contains a 3D geo
GeoElement geo = path.toGeoElement();
if (geo.isGeoElement3D() || (geo.isGeoList()
&& ((GeoList) geo).containsGeoElement3D())) {
ec.checkZooming(forPreviewable);
GeoPointND point = ec.kernel.getManager3D().Point3D(label, path, x,
y, z, !forPreviewable, coords2D);
return point;
}
// else use 2D
return ec.createNewPoint2D(label, forPreviewable, path, x, y, complex,
coords2D);
}
@Override
protected GeoElement midpoint(GeoSegmentND segment) {
if (((GeoElement) segment).isGeoElement3D()) {
return (GeoElement) ec.kernel.getManager3D().Midpoint(null,
segment);
}
return super.midpoint(segment);
}
@Override
protected GeoElement midpoint(GeoConicND conic) {
if (((GeoElement) conic).isGeoElement3D()) {
return (GeoElement) ec.kernel.getManager3D().Center(null, conic);
}
return super.midpoint(conic);
}
@Override
protected GeoElement midpoint(GeoPointND p1, GeoPointND p2) {
if (((GeoElement) p1).isGeoElement3D()
|| ((GeoElement) p2).isGeoElement3D()) {
AlgoMidpoint3D algo = new AlgoMidpoint3D(
ec.kernel.getConstruction(), p1, p2);
return algo.getPoint();
}
return super.midpoint(p1, p2);
}
@Override
public GeoElement[] regularPolygon(GeoPointND geoPoint1,
GeoPointND geoPoint2, GeoNumberValue value) {
if (geoPoint1.isGeoElement3D() || geoPoint2.isGeoElement3D()) {
return ec.kernel.getManager3D().RegularPolygon(null, geoPoint1,
geoPoint2, value, ec.getView().getDirection());
}
return ec.kernel.getAlgoDispatcher().RegularPolygon(null, geoPoint1,
geoPoint2, value);
}
@Override
protected AlgoElement segmentAlgo(Construction cons, GeoPointND p1,
GeoPointND p2) {
if (p1.isGeoElement3D() || p2.isGeoElement3D()) {
return new AlgoJoinPoints3D(cons, p1, p2, null, GeoClass.SEGMENT3D);
}
return super.segmentAlgo(cons, p1, p2);
}
@Override
protected GeoElement[] createCircle2(GeoPointND p0, GeoPointND p1) {
if (p0.isGeoElement3D() || p1.isGeoElement3D()) {
return createCircle2For3D(p0, p1);
}
return super.createCircle2(p0, p1);
}
/**
*
* @param p0
* center
* @param p1
* point on circle
* @return circle in the current plane
*/
protected GeoElement[] createCircle2For3D(GeoPointND p0, GeoPointND p1) {
return new GeoElement[] { ec.kernel.getManager3D().Circle3D(null, p0,
p1, ec.getView().getDirection()) };
}
@Override
protected GeoConicND circle(Construction cons, GeoPointND center,
GeoNumberValue radius) {
if (center.isGeoElement3D()) {
return circleFor3D(cons, center, radius);
}
return super.circle(cons, center, radius);
}
/**
*
* @param cons
* construction
* @param center
* center
* @param radius
* radius
* @return circle in the current plane
*/
protected GeoConicND circleFor3D(Construction cons, GeoPointND center,
GeoNumberValue radius) {
return ec.kernel.getManager3D().Circle3D(null, center, radius,
ec.getView().getDirection());
}
@Override
protected GeoElement[] angularBisector(GeoLineND g, GeoLineND h) {
if (g.isGeoElement3D() || h.isGeoElement3D()) {
return ec.kernel.getManager3D().AngularBisector3D(null, g, h);
}
return super.angularBisector(g, h);
}
@Override
protected GeoElement angularBisector(GeoPointND A, GeoPointND B,
GeoPointND C) {
if (A.isGeoElement3D() || B.isGeoElement3D() || C.isGeoElement3D()) {
return ec.kernel.getManager3D().AngularBisector3D(null, A, B, C);
}
return super.angularBisector(A, B, C);
}
@Override
protected GeoElement circleArcSector(GeoPointND A, GeoPointND B,
GeoPointND C, int type) {
GeoDirectionND orientation = ec.getView().getDirection();
return (GeoElement) ec.kernel.getManager3D().CircleArcSector3D(null, A,
B, C, orientation, type); // use view orientation
}
@Override
protected GeoElement semicircle(GeoPointND A, GeoPointND B) {
GeoDirectionND orientation = ec.getView().getDirection();
return (GeoElement) ec.kernel.getManager3D().Semicircle3D(null, A, B,
orientation); // use view orientation
}
@Override
protected GeoElement circumcircleArc(GeoPointND p1, GeoPointND p2,
GeoPointND p3) {
if (p1.isGeoElement3D() || p2.isGeoElement3D() || p3.isGeoElement3D()) {
return (GeoElement) ec.kernel.getManager3D().CircumcircleArc3D(null,
p1, p2, p3);
}
return super.circumcircleArc(p1, p2, p3);
}
@Override
protected GeoElement circumcircleSector(GeoPointND p1, GeoPointND p2,
GeoPointND p3) {
if (p1.isGeoElement3D() || p2.isGeoElement3D() || p3.isGeoElement3D()) {
return (GeoElement) ec.kernel.getManager3D()
.CircumcircleSector3D(null, p1, p2, p3);
}
return super.circumcircleSector(p1, p2, p3);
}
@Override
protected GeoElement[] tangent(GeoPointND a, GeoConicND c) {
return ec.kernel.getManager3D().Tangent3D(null, a, c);
}
@Override
protected GeoElement[] tangent(GeoLineND l, GeoConicND c) {
return ec.kernel.getManager3D().Tangent3D(null, l, c);
}
@Override
protected GeoElement[] tangent(GeoConicND c1, GeoConicND c2) {
return ec.kernel.getManager3D().CommonTangents3D(null, c1, c2);
}
@Override
protected GeoElementND polarLine(GeoPointND P, GeoConicND c) {
if (P.isGeoElement3D() || c.isGeoElement3D()) {
AlgoPolarLine3D algo = new AlgoPolarLine3D(
ec.kernel.getConstruction(), null, c, P);
return algo.getLine();
}
return super.polarLine(P, c);
}
@Override
protected GeoElement diameterLine(GeoLineND l, GeoConicND c) {
return ec.kernel.getManager3D().DiameterLine3D(null, l, c);
}
@Override
protected GeoElement diameterLine(GeoVectorND v, GeoConicND c) {
return ec.kernel.getManager3D().DiameterLine3D(null, v, c);
}
@Override
protected GeoElement lineBisector(GeoSegmentND segment) {
return ec.kernel.getManager3D().LineBisector3D(null, segment,
ec.getView().getDirection());
}
@Override
protected GeoElement lineBisector(GeoPointND a, GeoPointND b) {
return ec.kernel.getManager3D().LineBisector3D(null, a, b,
ec.getView().getDirection());
}
@Override
protected GeoConicND conic5(GeoPointND[] points) {
for (int i = 0; i < 5; i++) {
if (points[i].isGeoElement3D()) {
return ec.kernel.getManager3D().Conic3D(null, points);
}
}
return super.conic5(points);
}
@Override
protected GeoConicND ellipseHyperbola(GeoPointND a, GeoPointND b,
GeoPointND c, int type) {
return ec.kernel.getManager3D().EllipseHyperbola3D(null, a, b, c,
ec.getView().getDirection(), type);
}
@Override
protected GeoConicND parabola(GeoPointND a, GeoLineND l) {
if (a.isGeoElement3D() || l.isGeoElement3D()) {
return ec.kernel.getManager3D().Parabola3D(null, a, l);
}
return super.parabola(a, l);
}
@Override
protected GeoElement vectorPoint(GeoPointND a, GeoVectorND v) {
if (a.isGeoElement3D() || v.isGeoElement3D()) {
GeoPointND endPoint = (GeoPointND) ec.kernel.getManager3D()
.Translate3D(null, a, v)[0];
return ec.kernel.getManager3D().Vector3D(null, a, endPoint);
}
return super.vectorPoint(a, v);
}
@Override
protected GeoElement locus(GeoPointND a, GeoPointND b) {
if (a.isGeoElement3D() || b.isGeoElement3D()) {
return ec.kernel.getManager3D().Locus3D(null, a, b);
}
return super.locus(a, b);
}
}