/*
* Copyright 2006, United States Government as represented by the Administrator
* for the National Aeronautics and Space Administration. No copyright is
* claimed in the United States under Title 17, U.S. Code. All Other Rights
* Reserved.
*/
package gov.nasa.ial.mde.solver;
import gov.nasa.ial.mde.math.IntervalXY;
import gov.nasa.ial.mde.math.NumberModel;
import gov.nasa.ial.mde.math.PointXY;
import gov.nasa.ial.mde.solver.classifier.QuadraticClassifier;
import gov.nasa.ial.mde.solver.classifier.QuadraticClassifier.QuadraticType;
import gov.nasa.ial.mde.solver.features.individual.SlopeFeature;
import gov.nasa.ial.mde.solver.symbolic.AnalyzedEquation;
/**
* Subclass of SolvedGraph responsible for recording features unique to lines.
*
* @author Dr. Robert Shelton
* @version 1.0
* @since 1.0
*/
public class SolvedLine extends SolvedConic implements SlopeFeature {
/** Identify new features so we can access them with SolvedGraph.putFeature */
protected String[] newFeatures = {
"slope",
"inclination",
"slopeDefined",
"incrad", // inclination in radians
"reducedEquation" // in case the original is in an oddball form
};
/**
* Creates a solved line from the specified analyzed equation.
*
* @param equation the analyzed equation.
*/
public SolvedLine(AnalyzedEquation equation) {
super(equation);
/*
* QC is the QuadraticClassifier field in SolvedConic ID is one of the values associated
* with lines e.g. QuadraticClassifier.SLOPING_LINE
*/
QuadraticClassifier.QuadraticType ID = QC.getIdentity();
double alpha = QC.getRotation(); // rotation angle in degrees
/*
* Get the initial polynomial coefficients -- coeffs={a,b,c,d,e,f} where
* a*x^2+b*x*y+c*y^2+d*x+e*y+f=0 specifies the equation
*/
double[] coeffs = QC.getOriginalCoefficients();
putNewFeatures(newFeatures); // enable use of new features
//putFeature("graphName", "line"); // self-explanatory
putFeature("equationType", "linear equation"); // ditto
putFeature("graphClosure", "false"); // might be hard to determine in general
/*
* First take out rotation. This section determines how the equation should look if it were
* presented in cannonical form, i.e. equation defined by coeffs[3]*x+coeffs[4]*y+coeffs[5] = 0
* Note that the rotated case can only be recognized when the user enters something like
* (a*x + b*y + c)^2 = 0 in which the cannonical form is squared and equated to 0. This
* confuses the QC and requires treatment of this case to find the cannonical coefficients
*/
if (alpha != 0.0) {
double[] offsets = QC.getTranslation();
double[][] newAxes = QC.getNewAxes();
switch (ID) {
case HorizontalLine :
/*******************************************************************************
* i.e bPrime and v = newAxis[1][0*x + newAxis[1][1]*y
*/
coeffs[3] = newAxes[1][0];
coeffs[4] = newAxes[1][1];
coeffs[5] = -offsets[1];
break;
case VerticalLine :
/*******************************************************************************
* i.e. aPrime where u = newAxis[0][0]*x + newAxis[0][1]*y
*/
coeffs[3] = newAxes[0][0];
coeffs[4] = newAxes[0][1];
coeffs[5] = -offsets[0];
break;
default :
/*
* The only other single-line case is QC.SLOPING_LINE which is not recognized
* in the rotated case
*/
throw new IllegalArgumentException("ID " + ID + "illegal for rotated case.");
} // end switch
/*
* the equation must have been entered by the user in a funky form, so unscramble
*/
putFeature(
"reducedEquation",
QuadraticClassifier.getEquationOfALine(new PointXY(0.0, -coeffs[5] / coeffs[4]), alpha, analyzedEq.getActualVariables()));
/*
* to complete the fakery, we need to tell doLineFeatures that it's a sloping line,
* which it is
*/
ID = QuadraticType.SlopingLine;
} // end if
else if (coeffs[0] != 0.0 || coeffs[2] != 0.0) {
/*
* No rotation, but there are still quadratic terms, so the user has entered something
* like (x-2)^2 = 0. If we do nothing, then coeffs will look like coeffs = {1, 0, 0, 4, 0, 4}
* and the x-intercept will drop out as 1. Wrong! The answer is 2! Grab offsets to
* modify coeffs appropriately
*/
double[] offsets = QC.getTranslation();
switch (ID) { // we're in an else, so ID hasn't been dittled
case HorizontalLine :
/* const*(y-offsets[1])^2 = 0 */
coeffs[3] = 0.0; // shouldn't need to do this
coeffs[4] = 1.0;
coeffs[5] = -offsets[1];
putFeature(
"reducedEquation",
QuadraticClassifier.getEquationOfALine(new PointXY(0.0, offsets[1]), 0.0, analyzedEq.getActualVariables()));
break;
case VerticalLine :
/* const*(x-offset[0])^2 = 0 */
coeffs[3] = 1.0;
coeffs[4] = 0.0; // shouldn't need to do this
coeffs[5] = -offsets[0];
putFeature("reducedEquation", QuadraticClassifier.getEquationOfALine(offsets[0], analyzedEq.getActualVariables()));
break;
default :
throw new IllegalStateException("We should never be here.");
} // end switch
} // end if
/*
* Should work with cannonical coeffs or those appropriately modified for special cases
*/
doLineFeatures(coeffs[3], coeffs[4], coeffs[5], ID);
// getXIntercepts();
// getDomain();
// getRange();
// getSlope();
//System.out.println(getXMLString());
} // end SolvedLine
private void doLineFeatures(double a, double b, double c, QuadraticClassifier.QuadraticType ID) {
double M = 0.0; // slope
double z; // atan of slope i.e. incrad
IntervalXY D; // domain
IntervalXY R; // range
D = new IntervalXY(analyzedEq.getActualVariables()[0], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
D.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X | IntervalXY.EXCLUDE_HIGH_X);
R = new IntervalXY(analyzedEq.getActualVariables()[1], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
R.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X | IntervalXY.EXCLUDE_HIGH_X);
if ((ID == QuadraticType.SlopingLine) || (ID == QuadraticType.HorizontalLine)) {
putFeature("slopeDefined", "true");
putFeature("slope", new NumberModel(M = -a / b));
putFeature("incrad", new NumberModel(z = Math.atan(M)));
putFeature("inclination", new NumberModel(180.0 * z / Math.PI));
putFeature("domain", D);
}
switch (ID) {
case SlopingLine :
putFeature("graphName", "line"); // self-explanatory
if (M > 0.0)
putFeature("ascendingRegions", D);
if (M < 0.0)
putFeature("descendingRegions", D);
putFeature("range", R);
break;
case HorizontalLine : // no xIntercept
putFeature("graphName", "horizontal line"); // self-explanatory
putFeature("range", new IntervalXY(analyzedEq.getActualVariables()[1], -c / b, -c / b));
break;
case VerticalLine : // handle as a separate case
putFeature("graphName", "vertical line"); // self-explanatory
putFeature("slopeDefined", "false");
putFeature("inclination", new NumberModel(90.0));
putFeature("incrad", new NumberModel(Math.PI/2.0));
//putFeature("incrad", "pi/2");
putFeature("domain", new IntervalXY(analyzedEq.getActualVariables()[0], -c / a, -c / a));
putFeature("range", R);
/*
* putFeature ("reducedEquation", QuadraticClassifier.getEquationOfALine(-c/a,
* analyzedEquation.getActualVariables()));
*/
break;
default :
throw new IllegalArgumentException("Bad identity for a line: ID = " + ID);
} // end switch
} // end doLineFeatures
public double getSlope() {
Object value = this.getValue(SlopeFeature.PATH, SlopeFeature.KEY);
String slopeString = (String)value;
double slope = new Double(slopeString);
//System.out.println("Slope is: " + slope);
return slope;
}
public double getYIntercept()
{
Double[] array = getYIntercepts();
return array[0];
}
public double getXIntercept()
{
Double[] array = getXIntercepts();
return array[0];
}
} // end class SolvedLine