package org.geogebra.common.geogebra3D.kernel3D.geos;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoJoinPoints3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoRayPointVector3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Transform;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.geos.LimitedPath;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoRayND;
import org.geogebra.common.plugin.GeoClass;
/**
* 3D ray
*
*/
public class GeoRay3D extends GeoLine3D implements GeoRayND, LimitedPath {
/**
* @param c
* construction
* @param O
* start point
* @param Q
* end point
*/
public GeoRay3D(Construction c, GeoPointND O, GeoPointND Q) {
super(c, O, Q);
setStartPoint(O);
}
/**
* @param c
* construction
* @param O
* start point
*/
public GeoRay3D(Construction c, GeoPointND O) {
super(c);
setStartPoint(O);
}
/**
* @param construction
* construction
*/
public GeoRay3D(Construction construction) {
super(construction);
}
@Override
public GeoClass getGeoClassType() {
return GeoClass.RAY3D;
}
@Override
protected GeoCoordSys1D create(Construction cons1) {
return new GeoRay3D(cons1);
}
// Path3D interface
@Override
public double getMinParameter() {
return 0;
}
@Override
public boolean isValidCoord(double x) {
return (x >= 0);
}
@Override
public boolean isOnPath(Coords p, double eps) {
// first check global line
if (!super.isOnPath(p, eps)) {
return false;
}
// then check position on segment
return respectLimitedPath(p, eps);
}
@Override
public boolean respectLimitedPath(Coords p, double eps) {
if (Kernel.isEqual(p.getW(), 0, eps)) {
return false;
}
double d = p.sub(getStartInhomCoords()).dotproduct(getDirectionInD3());
if (d < -eps) {
return false;
}
return true;
}
// ///////////////////////////////////////
// LIMITED PATH
// ///////////////////////////////////////
private boolean allowOutlyingIntersections = false;
private boolean keepTypeOnGeometricTransform = true; // for mirroring,
// rotation, ...
@Override
final public boolean isLimitedPath() {
return true;
}
@Override
public boolean allowOutlyingIntersections() {
return allowOutlyingIntersections;
}
@Override
public void setAllowOutlyingIntersections(boolean flag) {
allowOutlyingIntersections = flag;
}
@Override
public boolean keepsTypeOnGeometricTransform() {
return keepTypeOnGeometricTransform;
}
@Override
public void setKeepTypeOnGeometricTransform(boolean flag) {
keepTypeOnGeometricTransform = flag;
}
@Override
public GeoElement[] createTransformedObject(Transform t, String label1) {
AlgoElement algoParent1 = keepTypeOnGeometricTransform
? getParentAlgorithm() : null;
// CREATE RAY
if (algoParent1 instanceof AlgoJoinPoints3D && t.isAffine()) {
// transform points
AlgoJoinPoints3D algo = (AlgoJoinPoints3D) algoParent1;
GeoPointND[] points = { algo.getP(), algo.getQ() };
points = t.transformPoints(points);
// if(t.isAffine()){
GeoElement ray = (GeoElement) kernel.getManager3D().Ray3D(label1,
points[0], points[1]);
ray.setVisualStyleForTransformations(this);
GeoElement[] geos = { ray, (GeoElement) points[0],
(GeoElement) points[1] };
return geos;
// }
/*
* else { GeoPoint inf = new GeoPoint(cons);
* inf.setCoords(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
* 1); inf = (GeoPoint)t.doTransform(inf); AlgoConicPartCircumcircle
* ae = new AlgoConicPartCircumcircle(cons,
* Transform.transformedGeoLabel(this), points[0],
* points[1],inf,GeoConicPart.CONIC_PART_ARC);
* cons.removeFromAlgorithmList(ae); GeoElement arc =
* ae.getConicPart(); arc.setVisualStyleForTransformations(this);
* GeoElement [] geos = {arc, points[0], points[1]}; return geos; }
*/
}
// create LINE
GeoElement transformedLine = t.getTransformedLine(this);
transformedLine.setLabel(label1);
GeoElement[] ret = { transformedLine };
return ret;
}
@Override
public boolean isAllEndpointsLabelsSet() {
return startPoint.isLabelSet();
}
@Override
public boolean isIntersectionPointIncident(GeoPoint p, double eps) {
if (allowOutlyingIntersections) {
return isOnFullLine(p.getCoordsInD3(), eps);
}
return isOnPath(p, eps);
}
@Override
public GeoElement copyInternal(Construction cons1) {
GeoRay3D ray = new GeoRay3D(cons1,
(GeoPointND) startPoint.copyInternal(cons1));
ray.set(this);
return ray;
}
@Override
public void set(GeoElementND geo) {
super.set(geo);
if (!geo.isGeoRay()) {
return;
}
if (!geo.isDefined()) {
setUndefined();
}
GeoRayND ray = (GeoRayND) geo;
setKeepTypeOnGeometricTransform(ray.keepsTypeOnGeometricTransform());
startPoint = GeoLine.updatePoint(cons, startPoint, ray.getStartPoint());
}
@Override
protected void getXMLtags(StringBuilder sb) {
super.getXMLtags(sb);
// allowOutlyingIntersections
sb.append("\t<outlyingIntersections val=\"");
sb.append(allowOutlyingIntersections);
sb.append("\"/>\n");
// keepTypeOnGeometricTransform
sb.append("\t<keepTypeOnTransform val=\"");
sb.append(keepTypeOnGeometricTransform);
sb.append("\"/>\n");
}
@Override
public boolean isGeoRay() {
return true;
}
@Override
public boolean respectLimitedPath(double parameter) {
return Kernel.isGreaterEqual(parameter, 0);
}
@Override
final protected void getCoordsXML(StringBuilder sb) {
// not needed here
}
@Override
public GeoElement copyFreeRay() {
GeoPointND startPoint1 = (GeoPointND) getStartPoint()
.copyInternal(cons);
Coords direction = getDirectionInD3();
GeoVector3D directionVec = new GeoVector3D(cons);
directionVec.setCoords(direction);
AlgoRayPointVector3D algo = new AlgoRayPointVector3D(cons, null,
startPoint1, directionVec);
return algo.getOutput(0);
}
}