/*
* 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.properties.MdeSettings;
import gov.nasa.ial.mde.solver.classifier.QuadraticClassifier;
import gov.nasa.ial.mde.solver.features.individual.FocalLengthFeature;
import gov.nasa.ial.mde.solver.features.individual.FocusFeature;
import gov.nasa.ial.mde.solver.features.individual.VertexFeature;
import gov.nasa.ial.mde.solver.symbolic.AnalyzedEquation;
/**
* Subclass of SolvedGraph responsible for recording features unique to parabolas.
*
* @author Dr. Robert Shelton
* @version 1.0
* @since 1.0
*
* Edits made by Andrew Rosen beginning 6/4/10
*/
//TODO: add extrema detection
public class SolvedParabola extends SolvedConic implements VertexFeature, FocalLengthFeature, FocusFeature{
/** Identify new features so we can access them with SolvedGraph.putFeature */
protected String[] newFeatures = {
"vertex",
"focalLength",
"focus",
"directrix",
"axis",
"axisInclination",
"directrixInclination",
"openDirection" };
/* enums for opening direction */
private final static int NO_D = 0, UP = 1, DOWN = 2, RIGHT = 3, LEFT = 4;
private int ope = NO_D;
/**
* Constructs a solved parabola for the specified analyzed equation.
*
* @param equation the analyzed equation.
*/
public SolvedParabola(AnalyzedEquation equation) {
super(equation);
// specificFeatureNames = new String[newFeatures.length];
// System.arraycopy(newFeatures, 0, specificFeatureNames, 0, newFeatures.length);
/* QC is the QuadraticClassifier field in SolvedConic */
double alpha = QC.getRotation(); // rotation angle in degrees
/*
* coeffs={a, b, c, d, e} where a(u-h)^2 + b(v-k)^2 + cu + dv + e = 0
*/
double[] coeffs = QC.getNormalizedCoefficients();
double[] transUV = QC.getTranslation(); // transUV={h,k}
double[] vertexUV = new double[2];
double axisInclination,
directrixInclination,
focalLength = 0.0,
t;
putNewFeatures(newFeatures); // enable use of new features
putFeature("graphName", "parabola"); // self-explanatory
putFeature("equationType", "conic section"); // ditto
putFeature("graphClosure", "false"); // might be hard to determine in
// general
/* figure out which way it opens in UV space */
/* default is ope=NO_D which will cause an exception */
if (Math.abs(coeffs[0]) > Math.abs(coeffs[1])) {
/*
* We are in the form a(u-h)^2 + dv + e = 0, so normalize out
* coefficient of v
*/
t = -1.0 / coeffs[3];
for (int i = 0; i < 5; i++)
coeffs[i] *= t;
if (coeffs[0] > 0.0)
ope = UP;
else
ope = DOWN;
focalLength = Math.abs(0.25 / coeffs[0]);
} // end if
else {
/*
* We are in the form b(v-k)^2 + cu + e = 0, so normalize out the
* coefficient of u
*/
t = -1.0 / coeffs[2];
for (int i = 0; i < 5; i++)
coeffs[i] *= t;
if (coeffs[1] > 0.0)
ope = RIGHT;
else
ope = LEFT;
focalLength = Math.abs(0.25 / coeffs[1]);
} // end if
/* first calculate vertex */
switch (ope) {
case UP :
vertexUV[0] = transUV[0];
vertexUV[1] = coeffs[4];
axisInclination = alpha + 90.0;
break;
case DOWN :
vertexUV[0] = transUV[0];
vertexUV[1] = coeffs[4];
axisInclination = alpha - 90.0;
break;
case RIGHT :
vertexUV[1] = transUV[1];
vertexUV[0] = coeffs[4];
axisInclination = alpha;
break;
case LEFT :
vertexUV[1] = transUV[1];
vertexUV[0] = coeffs[4];
axisInclination = alpha + 180.0;
break;
default :
throw new IllegalStateException("Should have computed a valid opening direction.");
} // end switch
/* normalize angles between -179.9999 and 180.0 */
directrixInclination = axisInclination - 90.0;
axisInclination = QuadraticClassifier.normalizeAngleInDegrees(axisInclination);
directrixInclination = QuadraticClassifier.normalizeAngleInDegrees(directrixInclination);
/* rotate vertex from UV to XY coordinate system */
PointXY vertex = new PointXY(QC.UV2XY(vertexUV));
putFeature("vertex", vertex);
putFeature("axis", "line given by " + QuadraticClassifier.getEquationOfALine(vertex, axisInclination, analyzedEq.getActualVariables()));
putFeature("axisInclination", new NumberModel(axisInclination));
putFeature("directrixInclination", new NumberModel(directrixInclination));
/*
* displacement of focus relative to vertex. Focus is located
* focalDistance along the axis from the vertex in the open direction
* of the parabola
*/
PointXY focalDisplacement =
new PointXY(focalLength * Math.cos(Math.PI * axisInclination / 180.0), focalLength * Math.sin(Math.PI * axisInclination / 180.0));
PointXY focus = vertex.sum(focalDisplacement); // self-explanatory
/*
* directrix is perpendicular to the axis, crossing at directrixPoint
* which is the mirror image of the focus
*/
PointXY directrixPoint = vertex.difference(focalDisplacement);
putFeature("focalLength", new NumberModel(focalLength));
putFeature("focus", focus);
putFeature(
"directrix",
"line given by " + QuadraticClassifier.getEquationOfALine(directrixPoint, directrixInclination, analyzedEq.getActualVariables()));
putFeature("openDirection", SolvedGraph.getGeneralDir(ope));
/* find domain, range and ascending/descending regions */
if (alpha == 0.0) { // otherwise much more complicated -- defer for now
IntervalXY D, R; // domain and range
IntervalXY ar, dr; // ascending/descending regions
switch (ope) {
case UP :
D = new IntervalXY(analyzedEq.getActualVariables()[0], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
D.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X | IntervalXY.EXCLUDE_HIGH_X);
putFeature("domain", D);
R = new IntervalXY(analyzedEq.getActualVariables()[1], vertex.y, Double.POSITIVE_INFINITY);
R.setEndPointExclusions(IntervalXY.EXCLUDE_HIGH_X);
putFeature("range", R);
ar = new IntervalXY(analyzedEq.getActualVariables()[0], vertex.x, Double.POSITIVE_INFINITY);
ar.setEndPointExclusions(IntervalXY.EXCLUDE_HIGH_X);
putFeature("ascendingRegions", ar);
dr = new IntervalXY(analyzedEq.getActualVariables()[0], Double.NEGATIVE_INFINITY, vertex.x);
dr.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X);
putFeature("descendingRegions", dr);
break;
case DOWN :
D = new IntervalXY(analyzedEq.getActualVariables()[0], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
D.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X | IntervalXY.EXCLUDE_HIGH_X);
putFeature("domain", D);
R = new IntervalXY(analyzedEq.getActualVariables()[1], Double.NEGATIVE_INFINITY, vertex.y);
R.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X);
putFeature("range", R);
dr = new IntervalXY(analyzedEq.getActualVariables()[0], vertex.x, Double.POSITIVE_INFINITY);
dr.setEndPointExclusions(IntervalXY.EXCLUDE_HIGH_X);
putFeature("descendingRegions", dr);
ar = new IntervalXY(analyzedEq.getActualVariables()[0], Double.NEGATIVE_INFINITY, vertex.x);
ar.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X);
putFeature("ascendingRegions", ar);
break;
case RIGHT :
D = new IntervalXY(analyzedEq.getActualVariables()[0], vertex.x, Double.POSITIVE_INFINITY);
D.setEndPointExclusions(IntervalXY.EXCLUDE_HIGH_X);
putFeature("domain", D);
R = new IntervalXY(analyzedEq.getActualVariables()[1], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
R.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X | IntervalXY.EXCLUDE_HIGH_X);
putFeature("range", R);
break;
case LEFT :
D = new IntervalXY(analyzedEq.getActualVariables()[0], Double.NEGATIVE_INFINITY, vertex.x);
D.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X);
putFeature("domain", D);
R = new IntervalXY(analyzedEq.getActualVariables()[1], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
R.setEndPointExclusions(IntervalXY.EXCLUDE_LOW_X | IntervalXY.EXCLUDE_HIGH_X);
putFeature("range", R);
break;
default :
throw new IllegalStateException("Invalid opening direction in SolvedParabola");
} // end switch
} // end if
if(MdeSettings.DEBUG){
System.out.println(getXMLString());
getYIntercepts();
getVertex();
getFocus();
}
//getMinima();
// getFocalLength();
} // end SolvedParabola
public PointXY getVertex() {
Object value = this.getValue(VertexFeature.PATH, VertexFeature.KEY);
String vertexString = (String)value;
//System.out.println("Getting vertex.\nVertex is : " + vertexString);
String[] split = vertexString.split(",");
split[0] = split[0].replace("(", "");
split[1] = split[1].replace(")", "");
double xPos = Double.valueOf(split[0]);
double yPos = Double.valueOf(split[1]);
return (new PointXY(xPos,yPos));
}
public PointXY getFocus() {
Object value = this.getValue(FocusFeature.PATH, FocusFeature.KEY);
String focusString = (String)value;
//System.out.println("Getting Focus.\nFocus is : " + focusString);
String[] split = focusString.split(",");
split[0] = split[0].replace("(", "");
split[1] = split[1].replace(")", "");
double xPos = Double.valueOf(split[0]);
double yPos = Double.valueOf(split[1]);
return (new PointXY(xPos,yPos));
}
public Double getFocalLength() {
Object value = this.getValue(FocalLengthFeature.PATH, FocalLengthFeature.KEY);
Double doubleValue = new Double((String)value);
//System.out.println("Getting Focal Length.\nFocal Length is : " + doubleValue);
return doubleValue;
}
} // end class SolvedParabola