package org.geogebra.common.geogebra3D.euclidian3D.draw;
import org.geogebra.common.euclidian.plot.CurvePlotter;
import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D;
import org.geogebra.common.geogebra3D.euclidian3D.Hitting;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.PlotterBrush;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.Renderer;
import org.geogebra.common.geogebra3D.euclidian3D.printer3D.ExportToPrinter3D;
import org.geogebra.common.geogebra3D.euclidian3D.printer3D.ExportToPrinter3D.Type;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.kernelND.CurveEvaluable;
/**
* @author ggb3D
*
* Drawable for GeoCurveCartesian3D
*
*/
public class DrawCurve3D extends Drawable3DCurves {
/** handle to the curve */
private CurveEvaluable curve;
/**
* @param a_view3d
* the 3D view where the curve is drawn
* @param curve
* the 3D curve to draw
*/
public DrawCurve3D(EuclidianView3D a_view3d, CurveEvaluable curve) {
super(a_view3d, (GeoElement) curve);
this.curve = curve;
}
@Override
public void drawGeometry(Renderer renderer) {
renderer.getGeometryManager().draw(getGeometryIndex());
}
@Override
protected boolean updateForItSelf() {
EuclidianView3D view = getView3D();
Renderer renderer = view.getRenderer();
PlotterBrush brush = renderer.getGeometryManager().getBrush();
brush.start(getReusableGeometryIndex());
brush.setThickness(getGeoElement().getLineThickness(),
(float) view.getScale());
brush.setAffineTexture(0f, 0f);
brush.setLength(1f);
double min, max;
if (curve instanceof GeoFunction) {
if (((GeoFunction) curve).hasInterval()) {
min = ((GeoFunction) curve).getIntervalMin();
max = ((GeoFunction) curve).getIntervalMax();
double minView = view.getXmin();
double maxView = view.getXmax();
if (min < minView) {
min = minView;
}
if (max > maxView) {
max = maxView;
}
} else {
min = view.getXmin();
max = view.getXmax();
}
} else {
min = curve.getMinParameter();
max = curve.getMaxParameter();
}
// Log.debug(min+","+max);
CurvePlotter.plotCurve(curve, min, max, view, brush, false,
CurvePlotter.Gap.MOVE_TO);
setGeometryIndex(brush.end());
return true;
}
@Override
public void exportToPrinter3D(ExportToPrinter3D exportToPrinter3D) {
if (isVisible()) {
exportToPrinter3D.export(this, Type.CURVE);
}
}
@Override
protected void updateForView() {
if (getView3D().viewChangedByZoom()
|| getView3D().viewChangedByTranslate()) {
updateForItSelf();
}
}
@Override
public int getPickOrder() {
return DRAW_PICK_ORDER_PATH;
}
@Override
public void addToDrawable3DLists(Drawable3DLists lists) {
addToDrawable3DLists(lists, DRAW_TYPE_CLIPPED_CURVES);
}
@Override
public void removeFromDrawable3DLists(Drawable3DLists lists) {
removeFromDrawable3DLists(lists, DRAW_TYPE_CLIPPED_CURVES);
}
private GeoPoint3D hittingPoint;
private Coords project;
private double[] lineCoords;
@Override
public boolean hit(Hitting hitting) {
if (waitForReset) { // prevent NPE
return false;
}
if (hittingPoint == null) {
hittingPoint = new GeoPoint3D(getGeoElement().getConstruction());
project = new Coords(4);
lineCoords = new double[2];
}
hittingPoint.setWillingCoords(hitting.origin);
hittingPoint.setWillingDirection(hitting.direction);
((Path) curve).pointChanged(hittingPoint);
Coords closestPoint = hittingPoint.getInhomCoordsInD3();
closestPoint.projectLine(hitting.origin, hitting.direction, project,
lineCoords);
// Log.debug("\n" + hitting.origin + "\nclosest point:\n" +
// closestPoint
// + "\nclosest point on line:\n" + project);
// check if point on line is visible
if (!hitting.isInsideClipping(project)) {
return false;
}
double d = getView3D().getScaledDistance(project, closestPoint);
if (d <= getGeoElement().getLineThickness() + 2) {
double z = -lineCoords[0];
double dz = getGeoElement().getLineThickness()
/ getView3D().getScale();
setZPick(z + dz, z - dz);
return true;
}
return false;
}
@Override
public boolean hitForList(Hitting hitting) {
if (hasGeoElementVisible() && getGeoElement().isPickable()) {
return hit(hitting);
}
return false;
}
}