/* * 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. * * Created on Mar 2, 2004 */ package gov.nasa.ial.mde.solver; import gov.nasa.ial.mde.math.AngleModel; import gov.nasa.ial.mde.math.NumberModel; import gov.nasa.ial.mde.solver.classifier.PolarClassifier; import gov.nasa.ial.mde.solver.numeric.PolarModel; import gov.nasa.ial.mde.solver.numeric.PolarTrochoidModel; import gov.nasa.ial.mde.solver.symbolic.AnalyzedEquation; /** * The class represents a solved Polar trochoid. * * @author Dr. Robert Shelton * @version 1.0 * @since 1.0 */ public class SolvedPolarTrochoid extends SolvedGraph { /** Identify new features so we can access them with SolvedGraph.putFeature */ protected String[] newFeatures = { "thetaMultiple", "hasLoops", "maxLength", "isConvex", "minLength", "loopAngles", "axis", "axisInclination", "oddMultiple" }; private final static double EPSILON = 1.0e-8; private final static int CARDIOID = 0, LOOPY = 1, LUMPY = 2; private double A, B, phi; // r = A*cos(n*(theta-phi)) + B /** * Constructs a solved Polar Trochoid from the specified analyzed equation. * * @param ae the analyzed equation. */ public SolvedPolarTrochoid(AnalyzedEquation ae) { PolarClassifier pc = (PolarClassifier) ae.getClassifier(); PolarTrochoidModel ptm = (PolarTrochoidModel) pc.getBestGuess(); int n = ptm.whichSignature + 1; double[] mv = ptm.modelVector; putFeature("equationPrint", ae.printEquation()); if (mv[1] == 0.0) { putFeature("graphName", "collection of radial lines through the origin"); return; } // end if for (int i = 0; i < mv.length; i++) if (i != 1) mv[i] /= mv[1]; mv[1] = 1.0; int loopCase; // flag for loops, lumps or cardioid double a = -mv[2]; double b = -mv[3]; A = PolarModel.amplitude(a, b); phi = PolarModel.phaseInRads(a, b) / n; B = -mv[0]; /*********************************************************************** * Nasty kludge to avoid writing a lot of extra code Basis: To make r = * A*cos(n*(theta-phi)) - B into r = A*cos(n*(theta-psi)) + B, we need * to add PI/n to phi in order to reverse the sign of the cosine * function, and then replace r with -r and theta with theta-PI **********************************************************************/ if (B < 0.0) { B = -B; phi += Math.PI * ((n & 1) - 1.0 / n); } // end if putNewFeatures(newFeatures); // enable use of new features putFeature("maxLength", new NumberModel(A + B)); putFeature("thetaMultiple", "" + n); if ((n & 1) == 1) putFeature("oddMultiple", "true"); else putFeature("oddMultiple", "false"); if (Math.abs(A - B) < EPSILON * (Math.abs(A) + Math.abs(b))) loopCase = SolvedPolarTrochoid.CARDIOID; else if (A > B) loopCase = SolvedPolarTrochoid.LOOPY; else { loopCase = SolvedPolarTrochoid.LUMPY; if (B < (n * n + 1.0) * A) putFeature("isConvex", "false"); else putFeature("isConvex", "true"); } // end else if (n == 1) switch (loopCase) { case SolvedPolarTrochoid.CARDIOID : { AngleModel am = new AngleModel(); am.setAngleInRads(phi); putFeature("axis", SolvedGraph.getCompassDir(180.0 + am .getDegrees()) + " to " + SolvedGraph.getCompassDir(am.getDegrees())); putFeature("axisInclination", am.getMFN()); putFeature("graphName", "cardioid"); return; } // end block case SolvedPolarTrochoid.LOOPY : { AngleModel am = new AngleModel(); am.setAngleInRads(phi); putFeature("axis", SolvedGraph.getCompassDir(180.0 + am .getDegrees()) + " to " + SolvedGraph.getCompassDir(am.getDegrees())); putFeature("axisInclination", am.getMFN()); putFeature("graphName", "loopWithinALoop"); putFeature("minLength", new NumberModel(A - B)); return; } // end block case SolvedPolarTrochoid.LUMPY : { AngleModel am = new AngleModel(); am.setAngleInRads(phi + Math.PI); putFeature("axis", SolvedGraph.getCompassDir(180.0 + am .getDegrees()) + " to " + SolvedGraph.getCompassDir(am.getDegrees())); putFeature("axisInclination", am.getMFN()); putFeature("graphName", "eccentricCircle"); putFeature("minLength", new NumberModel(B - A)); return; } // end block default : throw new IllegalStateException( "This ain't supposed to happen"); } // end switch /* general case -- n > 1 */ switch (loopCase) { case SolvedPolarTrochoid.CARDIOID : putFeature("graphName", "pinchedLoops"); putNewFeature("loopAngles", "graphObject", "loops", true); // make // a // new // node putNewFeature("loopAngles", "angleInfo", null, false); // no new // node for (int i = 0; i < n; i++) { AngleModel am = new AngleModel(); am.setAngleInRads(phi + 2.0 * i * Math.PI / n); putFeature("loopAngles", "angleInfo", am.getMFN()); } // end for i return; case SolvedPolarTrochoid.LUMPY : putFeature("graphName", "lumpyCircle"); putFeature("minLength", new NumberModel(B - A)); putNewFeature("loopAngles", "graphObject", "bulges", true); // make // a // new // node putNewFeature("loopAngles", "angleInfo", null, false); // no new // node for (int i = 0; i < n; i++) { AngleModel am = new AngleModel(); am.setAngleInRads(phi + 2.0 * i * Math.PI / n); putFeature("loopAngles", "angleInfo", am.getMFN()); } // end for i if (B < (n * n + 1.0) * A) { putNewFeature("loopAngles", "graphObject", "dents", true); // make // new // node putNewFeature("loopAngles", "angleInfo", null, false); // no // new // node for (int i = 0; i < n; i++) { AngleModel am = new AngleModel(); am.setAngleInRads(phi + (2.0 * i - 1.0) * Math.PI / n); putFeature("loopAngles", "angleInfo", am.getMFN()); } // end for i } // end if return; case SolvedPolarTrochoid.LOOPY : putNewFeature("loopAngles", "graphObject", "longer loops", true); putNewFeature("loopAngles", "angleInfo", null, false); for (int i = 0; i < n; i++) { AngleModel am = new AngleModel(); am.setAngleInRads(phi + 2.0 * i * Math.PI / n); putFeature("loopAngles", "angleInfo", am.getMFN()); } // end for i if ((n & 1) == 0) { putFeature("graphName", "alternatingLoops"); putNewFeature("loopAngles", "graphObject", "shorter loops", true); // make new node putNewFeature("loopAngles", "angleInfo", null, false); for (int i = 0; i < n; i++) { AngleModel am = new AngleModel(); am.setAngleInRads(phi + (2.0 * i - 1.0) * Math.PI / n); putFeature("loopAngles", "angleInfo", am.getMFN()); } // end for i } // end if else putFeature("graphName", "nestedLoops"); putFeature("minLength", new NumberModel(A - B)); return; default : throw new IllegalStateException("This can't be happening"); } // end switch } // end PolarTrochoidModel }