package org.geogebra.common.kernel.geos;
import java.util.ArrayList;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.arithmetic.MyDouble;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoPolyhedronInterface;
import org.geogebra.common.kernel.kernelND.GeoSegmentND;
import org.geogebra.common.plugin.EuclidianStyleConstants;
/**
* Parent (number+direction) for changing coords of prism, cylinder, etc.
*
* @author Mathieu
*
*/
public class ChangeableCoordParent {
private GeoNumeric changeableCoordNumber = null;
private GeoElement changeableCoordDirector = null;
private double startValue;
private Coords direction, direction2, centroid;
private boolean forPolyhedronNet = false;
private GeoPolyhedronInterface parent;
/**
*
* @param v
* value
* @return v as GeoNumeric if instance of and independent (return null
* otherwise)
*/
static public GeoNumeric getGeoNumeric(NumberValue v) {
if (v instanceof GeoNumeric) {
GeoNumeric geo = (GeoNumeric) v;
if (geo.isIndependent()) {
return geo;
}
}
return null;
}
/**
* set changeable coord parent to the polygon as part of polyhedron net
* (check first if num is not null)
*
* @param polygon
* polyhedron net face
* @param num
* value that fold/unfold the net
* @param polyhedron
* polyhedron parent
*/
static public void setPolyhedronNet(GeoPolygon polygon, GeoNumeric num,
GeoPolyhedronInterface polyhedron) {
if (num != null) {
ChangeableCoordParent ccp = new ChangeableCoordParent(polygon, num,
polyhedron);
polygon.setChangeableCoordParent(ccp);
// set segments (if not already done)
for (GeoSegmentND segment : polygon.getSegments()) {
segment.setChangeableCoordParentIfNull(ccp);
}
// set points (if not already done)
for (GeoPointND point : polygon.getPointsND()) {
point.setChangeableCoordParentIfNull(ccp);
}
}
}
/**
* constructor
*
* @param number
* number
* @param director
* director
*/
public ChangeableCoordParent(GeoNumeric number, GeoElement director) {
changeableCoordNumber = number;
changeableCoordDirector = director;
forPolyhedronNet = false;
}
/**
* constructor
*
* @param child
* child
* @param number
* number
* @param parent
* parent polyhedron
*/
public ChangeableCoordParent(GeoElement child, GeoNumeric number,
GeoPolyhedronInterface parent) {
changeableCoordNumber = number;
changeableCoordDirector = child;
forPolyhedronNet = true;
this.parent = parent;
}
/**
*
* @return number
*/
final public GeoNumeric getNumber() {
return changeableCoordNumber;
}
/**
*
* @return value of the number
*/
final public double getValue() {
return changeableCoordNumber.getValue();
}
/**
*
* @return director
*/
final public GeoElement getDirector() {
return changeableCoordDirector;
}
/**
* record number value
*
* @param view
* view calling
*/
final public void record(EuclidianView view) {
startValue = getValue();
if (direction == null) {
direction = new Coords(3);
}
if (forPolyhedronNet) {
if (view instanceof EuclidianView3D) {
if (centroid == null) {
centroid = new Coords(3);
}
parent.pseudoCentroid(centroid);
direction.setSub3(((EuclidianView3D) view).getCursor3D()
.getInhomCoordsInD3(), centroid);
} else {
direction.set(0, 0, 0);
}
} else {
direction.set3(changeableCoordDirector.getMainDirection());
}
}
/**
*
* @return start value
*/
final public double getStartValue() {
return startValue;
}
/**
* @param rwTransVec
* real world translation vector
* @param endPosition
* end position
* @param viewDirection
* view direction
* @param updateGeos
* list of geos
* @param tempMoveObjectList
* temporary list
* @param view
* view where the move occurs (if not keyboard)
* @return true on success
*/
final public boolean move(Coords rwTransVec, Coords endPosition,
Coords viewDirection, ArrayList<GeoElement> updateGeos,
ArrayList<GeoElement> tempMoveObjectList, EuclidianView view) {
GeoNumeric var = getNumber();
if (var == null) {
return false;
}
if (endPosition == null) { // comes from arrows keys -- all is added
var.setValue(var.getValue() + rwTransVec.getX() + rwTransVec.getY()
+ rwTransVec.getZ());
GeoElement.addChangeableCoordParentNumberToUpdateList(var,
updateGeos, tempMoveObjectList);
return true;
}
if (viewDirection == null) { // may come from 2D view, e.g.
// EuclidianController.moveDependent()
// see
// https://play.google.com/apps/publish/?dev_acc=05873811091523087820#ErrorClusterDetailsPlace:p=org.geogebra.android&et=CRASH&sh=false&lr=LAST_7_DAYS&ecn=java.lang.NullPointerException:+Attempt+to+invoke+virtual+method+'double+org.geogebra.a.m.a.j.e(org.geogebra.a.m.a.j)'+on+a+null+object+reference&tf=SourceFile&tc=%2509at+org.geogebra.common.kernel.geos.ChangeableCoordParent.move(ChangeableCoordParent.java:202)&tm=a&nid&an&c&s=new_status_desc&ed=1480452507515
return false;
}
// else: comes from mouse
if (direction2 == null) {
direction2 = new Coords(3);
}
direction2.setAdd3(direction, direction2.setMul(viewDirection,
-viewDirection.dotproduct3(direction)));
double ld = direction2.dotproduct3(direction2);
if (Kernel.isZero(ld)) {
return false;
}
double shift = direction2.dotproduct3(rwTransVec) / ld;
if (!MyDouble.isFinite(shift)) {
return false;
}
double val = getStartValue() + shift;
if (!forPolyhedronNet) {
switch (view.getPointCapturingMode()) {
case EuclidianStyleConstants.POINT_CAPTURING_STICKY_POINTS:
// TODO
break;
default:
case EuclidianStyleConstants.POINT_CAPTURING_AUTOMATIC:
if (!view.isGridOrAxesShown()) {
break;
}
case EuclidianStyleConstants.POINT_CAPTURING_ON:
case EuclidianStyleConstants.POINT_CAPTURING_ON_GRID:
double g = view.getGridDistances(0);
double valRound = Kernel.roundToScale(val, g);
if (view.getPointCapturingMode() == EuclidianStyleConstants.POINT_CAPTURING_ON_GRID
|| (Math.abs(valRound - val) < g
* view.getEuclidianController()
.getPointCapturingPercentage())) {
val = valRound;
}
break;
}
}
var.setValue(val);
GeoElement.addChangeableCoordParentNumberToUpdateList(var, updateGeos,
tempMoveObjectList);
return true;
}
}