/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
This file is part of GeoGebra.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation.
*/
package org.geogebra.common.geogebra3D.kernel3D.algos;
import org.geogebra.common.geogebra3D.kernel3D.MyPoint3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoLocus3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoLocusND;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.util.MyMath;
/**
* locus line for Q dependent on P
*/
public class AlgoLocus3D extends AlgoLocusND<MyPoint3D> {
private double[] maxZdist, farZmin, farZmax;
private static int MAX_Z_PIXEL_DIST = MAX_X_PIXEL_DIST;
/**
* @param cons
* construction
* @param Q
* locus point
* @param P
* moving point
* @param min_steps
* min number of steps
* @param registerCE
* whether to listen to zoom/pan
*/
public AlgoLocus3D(Construction cons, GeoPointND Q, GeoPointND P,
int min_steps, boolean registerCE) {
super(cons, Q, P, min_steps, registerCE);
}
/**
* @param cons
* construction
* @param label
* output label
* @param Q
* locus point
* @param P
* moving point
*/
public AlgoLocus3D(Construction cons, String label, GeoPointND Q,
GeoPointND P) {
super(cons, label, Q, P);
}
@Override
protected void createMaxDistances() {
super.createMaxDistances();
maxZdist = new double[3];
farZmin = new double[3];
farZmax = new double[3];
}
@Override
protected void setMaxDistances(int i) {
super.setMaxDistances(i);
if (i == 2) { // 3D view
maxZdist[i] = MAX_Z_PIXEL_DIST / kernel.getZscale(i);
double zmin = kernel.getZmin(i);
double zmax = kernel.getZmax(i);
double widthRW = zmax - zmin;
farZmin[i] = zmin - widthRW / 2;
farZmax[i] = zmax + widthRW / 2;
} else {
maxZdist[i] = Double.POSITIVE_INFINITY; // we don't check z for 2D
// views
farZmin[i] = Double.NEGATIVE_INFINITY;
farZmax[i] = Double.POSITIVE_INFINITY;
}
}
@Override
protected void createStartPos(Construction cons1) {
startQPos = new GeoPoint3D(cons1);
if (movingPoint.isGeoElement3D()) {
startPPos = new GeoPoint3D(cons1);
} else {
startPPos = new GeoPoint(cons1);
}
}
@Override
protected GeoLocus3D newGeoLocus(Construction cons1) {
return new GeoLocus3D(cons1);
}
@Override
protected boolean isFarAway(GeoPointND point, int i) {
Coords coords = point.getInhomCoordsInD3();
return isFarAway(coords.getX(), coords.getY(), coords.getZ(), i);
}
@Override
protected boolean distanceOK(GeoPointND point, int i) {
double[] min = { farXmin[i], farYmin[i], farZmin[i] };
double[] max = { farXmax[i], farYmax[i], farZmax[i] };
Coords coords = point.getInhomCoordsInD3();
// if last point Q' was far away and Q is far away
// then the distance is probably OK (return true),
// so we probably don't need smaller step,
// except if the rectangle of the segment Q'Q
// intersects the near to screen rectangle
// (it will probably not be on the screen anyway)
double minX = lastX;
double minY = lastY;
double minZ = lastZ;
double maxX = coords.getX();
double maxY = coords.getY();
double maxZ = coords.getZ();
if (coords.getX() < minX) {
minX = coords.getX();
maxX = lastX;
}
if (coords.getY() < minY) {
minY = coords.getY();
maxY = lastY;
}
if (coords.getZ() < minZ) {
minZ = coords.getZ();
maxZ = lastZ;
}
boolean ok2d = !MyMath.intervalsIntersect(minX, maxX, min[0], max[0])
|| !MyMath.intervalsIntersect(minY, maxY, min[1], max[1]);
return i < 2 ? ok2d
: (ok2d || !MyMath.intervalsIntersect(minZ, maxZ, min[2],
max[2]));
}
@Override
protected boolean distanceSmall(GeoPointND point, boolean orInsteadOfAnd) {
Coords coords = point.getInhomCoordsInD3();
boolean[] distSmall = new boolean[3];
for (int i = 0; i < distSmall.length; i++) {
distSmall[i] = Math.abs(coords.getX() - lastX) < maxXdist[i]
&& Math.abs(coords.getY() - lastY) < maxYdist[i]
&& Math.abs(coords.getZ() - lastZ) < maxZdist[i];
}
if (orInsteadOfAnd) {
for (int i = 0; i < distSmall.length; i++) {
if (distSmall[i] && visibleEV[i]) {
return true;
}
}
return false;
}
for (int i = 0; i < distSmall.length; i++) {
if (!distSmall[i] && visibleEV[i]) {
return false;
}
}
return true;
}
@Override
protected void insertPoint(GeoPointND point, boolean lineTo) {
Coords coords = point.getInhomCoordsInD3();
insertPoint(coords.getX(), coords.getY(), coords.getZ(), lineTo);
}
private void insertPoint(double x, double y, double z, boolean lineTo) {
pointCount++;
// Application.debug("insertPoint: " + x + ", " + y + ", lineto: " +
// lineTo);
((GeoLocus3D) locus).insertPoint(x, y, z, lineTo);
lastX = x;
lastY = y;
lastZ = z;
for (int i = 0; i < lastFarAway.length; i++) {
lastFarAway[i] = isFarAway(lastX, lastY, lastZ, i);
}
}
private double lastZ;
private boolean isFarAway(double x, double y, double z, int i) {
boolean farAway = (x > farXmax[i] || x < farXmin[i] || y > farYmax[i]
|| y < farYmin[i] || z > farZmax[i] || z < farZmin[i]);
return farAway;
}
@Override
protected boolean differentFromLast(GeoPointND point) {
Coords coords = point.getInhomCoordsInD3();
return coords.getX() != lastX || coords.getY() != lastY
|| coords.getZ() != lastZ;
}
@Override
protected boolean areEqual(GeoPointND p1, GeoPointND p2) {
return ((GeoElement) p1).isEqual(p2);
}
@Override
protected MyPoint3D[] createQCopyCache(int length) {
return new MyPoint3D[length];
}
@Override
protected void setQCopyCache(MyPoint3D copy, GeoPointND point) {
Coords coords = point.getInhomCoordsInD3();
copy.setX(coords.getX());
copy.setY(coords.getY());
copy.setZ(coords.getZ());
}
@Override
protected MyPoint3D newCache() {
return new MyPoint3D();
}
}