/*
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.kernel.statistics;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoPoint;
/**
* FitLineY of a list. adapted from AlgoListMax
*
* @author Michael Borcherds
* @version 14-01-2008
*/
public class AlgoFitLineX extends AlgoElement {
private GeoList geoList; // input
private GeoLine g; // output
public AlgoFitLineX(Construction cons, String label, GeoList geoList) {
this(cons, geoList);
g.setLabel(label);
}
public AlgoFitLineX(Construction cons, GeoList geoList) {
super(cons);
this.geoList = geoList;
g = new GeoLine(cons);
// ignore default (implicit)
// for FitXXX we always want "y=..."
g.setToExplicit();
setInputOutput(); // for AlgoElement
compute();
}
@Override
public Commands getClassName() {
return Commands.FitLineX;
}
@Override
protected void setInputOutput() {
input = new GeoElement[1];
input[0] = geoList;
setOnlyOutput(g);
setDependencies(); // done by AlgoElement
}
public GeoLine getFitLineX() {
return g;
}
@Override
public final void compute() {
int size = geoList.size();
if (!geoList.isDefined() || size <= 1) {
g.setUndefined();
return;
}
double sigmax = 0;
double sigmay = 0;
// double sigmaxx=0; not needed
double sigmayy = 0;
double sigmaxy = 0;
for (int i = 0; i < size; i++) {
GeoElement geo = geoList.get(i);
if (geo instanceof GeoPoint) {
double xy[] = new double[2];
((GeoPoint) geo).getInhomCoords(xy);
double x = xy[0];
double y = xy[1];
sigmax += x;
sigmay += y;
// sigmaxx+=x*x; not needed
sigmaxy += x * y;
sigmayy += y * y;
} else {
g.setUndefined();
return;
}
}
// x on y regression line
// (x - sigmax / n) = (Syy / Sxy)*(y - sigmay / n)
// rearranged to eliminate all divisions
// g.y = size * sigmax * sigmay - size * size * sigmaxy;
// g.x = size * size * sigmayy - size * sigmay * sigmay;
// g.z = size * sigmay * sigmaxy - size * sigmayy * sigmax;
// (g.x)x + (g.y)y + g.z = 0
// more accurate, see #5230
double Sxy = sigmaxy - sigmax * sigmay / size;
double Syy = sigmayy - sigmay * sigmay / size;
double mux = sigmax / size;
double muy = sigmay / size;
g.x = -Syy;
g.y = Sxy;
g.z = -Sxy * muy + Syy * mux;
// #5294
if (Kernel.isZero(g.x) || Kernel.isZero(g.y) || Kernel.isZero(g.z)) {
return;
}
// normalize coefficients (copied from
// GeoLine.getnormalizedCoefficients())
// #5230
while (Math.abs(g.x) < 0.5 && Math.abs(g.y) < 0.5
&& Math.abs(g.z) < 0.5) {
g.x *= 2;
g.y *= 2;
g.z *= 2;
}
while (Math.abs(g.x) > 1 && Math.abs(g.y) > 1 && Math.abs(g.z) > 1) {
g.x /= 2;
g.y /= 2;
g.z /= 2;
}
}
}