/*
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.
*/
/*
* AlgoAttachCopyToView.java
*
* Created on 24. September 2001, 21:37
*/
package org.geogebra.common.kernel.algos;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.MatrixTransformable;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.Function;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoConicPart;
import org.geogebra.common.kernel.geos.GeoCurveCartesian;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoly;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.main.settings.EuclidianSettings;
import org.geogebra.common.util.MyMath;
/**
*
* @author Zbynek
*/
public class AlgoAttachCopyToView extends AlgoTransformation {
private MatrixTransformable out;
private GeoElement inGeo, outGeo;
private GeoNumberValue viewID;
private GeoPointND corner1, corner3, screenCorner1, screenCorner3;
/**
* Creates new apply matrix algorithm
*
* @param cons
* construction
* @param label
* label for output
* @param in
* input element
* @param viewID
* id of Euclidian view (0 = no,1 = EV1,2=EV2)
* @param corner1
* first real world point
* @param corner3
* second real world point
* @param screenCorner1
* screen point corresponding to corner1
* @param screenCorner3
* screen point corresponding to corner3
*/
public AlgoAttachCopyToView(Construction cons, String label,
GeoElementND in, GeoNumberValue viewID, GeoPointND corner1,
GeoPointND corner3, GeoPointND screenCorner1,
GeoPointND screenCorner3) {
this(cons, in, viewID, corner1, corner3, screenCorner1, screenCorner3);
outGeo.setLabel(label);
}
/**
* Creates new apply matrix algorithm
*
* @param cons
* construction
* @param in
* input element
* @param viewID
* id of Euclidian view (0 = no,1 = EV1,2=EV2)
* @param corner1
* first real world point
* @param corner3
* second real world point
* @param screenCorner1
* screen point corresponding to corner1
* @param screenCorner3
* screen point corresponding to corner3
*/
public AlgoAttachCopyToView(Construction cons, GeoElementND in,
GeoNumberValue viewID, GeoPointND corner1, GeoPointND corner3,
GeoPointND screenCorner1, GeoPointND screenCorner3) {
super(cons);
this.viewID = viewID;
this.corner1 = corner1;
this.corner3 = corner3;
this.screenCorner1 = screenCorner1;
this.screenCorner3 = screenCorner3;
inGeo = in.toGeoElement();
if ((inGeo instanceof GeoPoly) || inGeo.isLimitedPath()) {
outGeo = in.copyInternal(cons);
out = (MatrixTransformable) outGeo;
} else if (inGeo.isGeoList()) {
outGeo = new GeoList(cons);
} else if (inGeo instanceof GeoFunction) {
outGeo = inGeo.copy();
} else {
out = (MatrixTransformable) inGeo.copy();
outGeo = out.toGeoElement();
}
setInputOutput();
compute();
cons.registerEuclidianViewCE(this);
}
@Override
public Commands getClassName() {
return Commands.AttachCopyToView;
}
// for AlgoElement
@Override
protected void setInputOutput() {
input = new GeoElement[6];
input[0] = inGeo;
input[1] = viewID.toGeoElement();
input[2] = corner1.toGeoElement();
input[3] = corner3.toGeoElement();
input[4] = screenCorner1.toGeoElement();
input[5] = screenCorner3.toGeoElement();
setOutputLength(1);
setOutput(0, outGeo);
setDependencies(); // done by AlgoElement
}
/**
* Returns the resulting element
*
* @return resulting element
*/
@Override
public GeoElement getResult() {
return outGeo;
}
@Override
public final void compute() {
int view = (int) viewID.getDouble();
// #5014
// use Settings so we don't need to initialise EV2
EuclidianSettings ev = null;
if (view == 1 || view == 2) {
ev = kernel.getApplication().getSettings().getEuclidian(view);
}
if (ev == null && view != 0) {
outGeo.setUndefined();
return;
}
if (inGeo.isGeoList()) {
transformList((GeoList) inGeo, (GeoList) outGeo);
return;
}
if (!inGeo.isGeoFunction()) {
outGeo.set(inGeo);
}
if (!outGeo.isDefined()) {
return;
}
if (view == 0) {
return;
}
Coords c1 = corner1.getCoordsInD3();
Coords c3 = corner3.getCoordsInD3();
Coords c5 = screenCorner1.getCoordsInD3();
Coords c7 = screenCorner3.getCoordsInD3();
double c1x = ev.toRealWorldCoordX(c5.getX());
double c1y = ev.toRealWorldCoordY(c5.getY());
double c3x = ev.toRealWorldCoordX(c7.getX());
double c3y = ev.toRealWorldCoordY(c7.getY());
double[][] m1 = MyMath.adjoint(c1.getX(), c1.getY(), 1, c3.getX(),
c3.getY(), 1, c1.getX(), c3.getY(), 1);
double[][] m2 = new double[][] { { c1x, c3x, c1x }, { c1y, c3y, c3y },
{ 1, 1, 1 } };
double[][] m = MyMath.multiply(m2, m1);
if (!(inGeo instanceof GeoFunction)) {
out.matrixTransform(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1],
m[1][2], m[2][0], m[2][1], m[2][2]);
// TODO check why we need this when result has points on it
outGeo.updateCascade();
} else {
transformFunction(m[0][0] / m[2][2], m[0][2] / m[2][2],
m[1][1] / m[2][2], m[1][2] / m[2][2]);
}
}
private void transformFunction(double d, double e, double f, double g) {
Function fun = ((GeoFunction) inGeo).getFunction();
ExpressionNode expr = fun.getExpression().getCopy(kernel);
expr = expr.replace(fun.getFunctionVariable(),
new ExpressionNode(kernel, fun.getFunctionVariable())
.multiply(1 / d).plus(-e / d))
.wrap();
Function fun2 = new Function(expr.multiply(f).plus(g),
fun.getFunctionVariable());
((GeoFunction) outGeo).setFunction(fun2);
}
@Override
protected void setTransformedObject(GeoElement g, GeoElement g2) {
inGeo = g;
outGeo = g2;
if (!(out instanceof GeoList)
&& (outGeo instanceof MatrixTransformable)) {
out = (MatrixTransformable) outGeo;
}
}
@Override
protected GeoElement getResultTemplate(GeoElement geo) {
if (geo instanceof GeoFunction) {
return new GeoCurveCartesian(cons);
}
return super.getResultTemplate(geo);
}
@Override
protected void transformLimitedPath(GeoElement a, GeoElement b) {
if (!(a instanceof GeoConicPart)) {
super.transformLimitedPath(a, b);
} else {
super.transformLimitedConic(a, b);
}
}
/**
* @param viewID2
* new EV ID (1 or 2)
*/
public void setEV(int viewID2) {
input[1].removeAlgorithm(this);
viewID = new GeoNumeric(cons, viewID2);
input[1] = viewID.toGeoElement();
}
@Override
public double getAreaScaleFactor() {
return 1;
}
}