package org.geogebra.commands;
import java.util.Locale;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.commands.AlgebraProcessor;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.main.App;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.lang.Unicode;
import org.geogebra.desktop.main.AppDNoGui;
import org.geogebra.desktop.main.LocalizationD;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@SuppressWarnings("javadoc")
public class CommandsTest extends Assert{
static AppDNoGui app;
static AlgebraProcessor ap;
private static String syntax;
private static void t(String input, String expected){
testSyntax(input, new String[] { expected }, app, ap,
StringTemplate.xmlTemplate);
}
private static void t(String input, String expected, StringTemplate tpl) {
testSyntax(input, new String[] { expected }, app, ap, tpl);
}
public static void t(String s, String[] expected, StringTemplate tpl) {
testSyntax(s, expected, app, ap, tpl);
}
public static void t(String s, String[] expected) {
testSyntax(s, expected, app, ap, StringTemplate.xmlTemplate);
}
public static void testSyntax(String s, String[] expected, App app1,
AlgebraProcessor proc, StringTemplate tpl) {
if(syntaxes==-1000){
Throwable t = new Throwable();
String cmdName = t.getStackTrace()[2].getMethodName().substring(3);
syntax = app1.getLocalization().getCommand(cmdName + ".Syntax");
syntaxes = 0;
for (int i = 0; i < syntax.length(); i++) {
if (syntax.charAt(i) == '[') {
syntaxes++;
}
}
String syntax3D = app1.getLocalization()
.getCommand(
cmdName + ".Syntax3D");
if (syntax3D.contains("[")) {
syntax += "\n" + syntax3D;
}
for (int i = 0; i < syntax3D.length(); i++) {
if (syntax3D.charAt(i) == '[') {
syntaxes++;
}
}
System.out.println();
System.out.print(cmdName);
/*
// This code helps to force timeout for each syntax. Not used at the moment.
GeoGebraCAS cas = (GeoGebraCAS) app.getKernel()
.getGeoGebraCAS();
try {
cas.getCurrentCAS().evaluateRaw("caseval(\"timeout 8\")");
} catch (Throwable e) {
App.error("CAS error " + e);
}
*/
}
Throwable t = null;
GeoElementND[] result = null;
try {
result = proc.processAlgebraCommandNoExceptionHandling(s,
false, TestErrorHandler.INSTANCE, false, null);
}catch (Throwable e) {
t = e;
}
syntaxes--;
assertNull(t);
Assert.assertNotNull(s,result);
// for (int i = 0; i < result.length; i++) {
// String actual = result[i].toValueString(tpl);
// System.out.println("\"" + actual + "\",");
// }
Assert.assertEquals(s + " count:", expected.length, result.length);
for (int i = 0; i < expected.length; i++) {
String actual = result[i].toValueString(tpl);
Assert.assertEquals(s + ":" + actual, expected[i], actual);
}
System.out.print("+");
}
private static int syntaxes = -1000;
@Before
public void resetSyntaxes(){
syntaxes = -1000;
app.getKernel().clearConstruction(true);
}
@After
public void checkSyntaxes(){
Assert.assertTrue("unchecked syntaxes: " + syntaxes + syntax,
syntaxes <= 0);
}
@BeforeClass
public static void setupApp() {
app = new AppDNoGui(new LocalizationD(3), false);
app.setLanguage(Locale.US);
ap = app.getKernel().getAlgebraProcessor();
// make sure x=y is a line, not plane
app.getGgbApi().setPerspective("1");
// Setting the general timeout to 11 seconds. Feel free to change this.
app.getKernel().getApplication().getSettings().getCasSettings().setTimeoutMilliseconds(11000);
}
@Test
public void testQuadricExpr() {
t("-y^2=z-1", "-y" + Unicode.Superscript_2 + " + 0z"
+ Unicode.Superscript_2 + " - z = -1");
t("y^2=1-z", "y" + Unicode.Superscript_2 + " + 0z"
+ Unicode.Superscript_2 + " + z = 1");
}
@Test
public void listArithmetic() {
t("{1,2,3}*2", "{2, 4, 6}");
t("{1,2,3}+3", "{4, 5, 6}");
t("list1:={1,2,3}", "{1, 2, 3}");
t("listF:={x, 2 * x,3 * x+1}", "{x, (2 * x), (3 * x) + 1}");
t("matrix1:={{1, 2, 3}, {2, 4, 6}, {3, 6, 9}}",
"{{1, 2, 3}, {2, 4, 6}, {3, 6, 9}}");
t("aa:=1", "1");
t("matrix2:={{aa}}", "{{1}}");
// app.getKernel().lookupLabel("matrix2").setFixed(true);
t("list1(1)", "1");
t("list1(4)", "NaN");
t("list1(0)", "NaN");
t("list1(-1)", "3");
t("list1(-5)", "NaN");
t("list1(1,2)", "NaN");
t("listF(1)", "x");
t("listF(2)", "(2 * x)");
t("listF(2,7)", "14");
t("matrix1(2)", "{2, 4, 6}");
t("matrix1(-1)", "{3, 6, 9}");
t("matrix1(-5)", "{NaN, NaN, NaN}");
t("matrix1(2,3)", "6");
t("matrix1(2,3,4)", "NaN");
t("matrix1(2,-1)", "6");
t("matrix1(5,2)", "NaN");
t("matrix1(2,5)", "NaN");
t("matrix2(1,2)", "NaN");
t("matrix2(2,1)", "NaN");
t("Delete[list1]", new String[] {});
t("Delete[matrix1]", new String[] {});
}
@Test
public void tuples() {
t("(1..2,1..2)", "{(1, 1), (2, 2)}");
}
private static GeoElement get(String label) {
return app.getKernel().lookupLabel(label);
}
@Test
public void listPropertiesTest() {
t("mat1={{1,2,3}}", "{{1, 2, 3}}");
Assert.assertTrue(((GeoList) get("mat1")).isEditableMatrix());
t("slider1=7", "7");
t("mat2={{1,2,slider1}}", "{{1, 2, 7}}");
Assert.assertTrue(((GeoList) get("mat2")).isEditableMatrix());
t("mat2={{1,2,slider1},Reverse[{1,2,3}]}", "{{1, 2, 7}, {3, 2, 1}}");
Assert.assertFalse(((GeoList) get("mat2")).isEditableMatrix());
}
@Test
public void operationSequence() {
Assert.assertEquals(StringUtil.fixVerticalBars("1..2"), "1"
+ Unicode.ellipsis + "2");
t("3.2..7.999", "{3, 4, 5, 6, 7, 8}");
t("-3.2..3.2", "{-3, -2, -1, 0, 1, 2, 3}");
t("3.2..-2", "{3, 2, 1, 0, -1, -2}");
t("seqa=2*(1..5)", "{2, 4, 6, 8, 10}");
assertEquals("<expression label =\"seqa\" exp=\"(2 * (1"
+ Unicode.ellipsis + "5))\"/>",
app.getGgbApi().getXML("seqa").split("\n")[0]);
t("seqa=(1..3)+3", "{4, 5, 6}");
assertEquals(
"<expression label =\"seqa\" exp=\"(1" + Unicode.ellipsis
+ "3) + 3\"/>",
app.getGgbApi().getXML("seqa").split("\n")[0]);
}
@Test
public void cmdMidpoint(){
t("Midpoint[(0,0),(2,2)]","(1, 1)");
t("Midpoint[0<x<2]","1");
t("Midpoint[Segment[(0,0),(2,2)]]","(1, 1)");
t("Midpoint[(x-1)^2+(y-1)^2=pi]","(1, 1)");
}
@Test
public void cmdIsInRegion(){
t("IsInRegion[(0,0),Circle[(1,1),2]]","true");
t("IsInRegion[(0,0),Circle[(1,1),1]]","false");
t("IsInRegion[(0,0,0),x+y+z=1]","false");
t("IsInRegion[(0,0,0),x+y+z=0]","true");
t("IsInRegion[(0,0,0),Polygon[(0,0,1),(1,0,0),(0,1,0)]]","false");
t("IsInRegion[(1/3,1/3,1/3),Polygon[(0,0,1),(1,0,0),(0,1,0)]]","true");
//move the centroid a bit in z-axis, it should no longer be inside
t("IsInRegion[(1/3,1/3,1/2),Polygon[(0,0,1),(1,0,0),(0,1,0)]]","false");
}
@Test
public void cmdCross(){
t("Cross[(0,0,1),(1,0,0)]","(0, 1, 0)");
t("Cross[(0,0,1),(0,1,0)]","(-1, 0, 0)");
t("Cross[(0,0,1),(0,0,1)]","(0, 0, 0)");
t("Cross[(0,1),(2,0)]","-2");
t("Cross[(0,1),(0,2)]","0");
}
@Test
public void functionDependentPoly() {
t("s(x,y)=x+y", "x + y");
t("s(1,2)*x=1", "x = 0.3333333333333333");
}
@Test
public void cmdDot(){
t("Dot[(0,0,1),(1,0,0)]","0");
t("Dot[(0,0,1),(0,0,1)]","1");
t("Dot[(0,3),(0,2)]","6");
}
@Test
public void cmdNormalize() {
t("Normalize[{1,3,2}]", "{0, 1, 0.5}");
t("Normalize[{(1,1),(3,1),(2,1)}]", "{(0, 0), (1, 0), (0.5, 0)}");
}
@Test
public void cmdDataFunction(){
t("DataFunction[]", "DataFunction[{}, {},x]");
t("DataFunction[]", new String[] { "DataFunction[x]" },
StringTemplate.defaultTemplate);
}
@Test
public void cmdAreCongruent() {
t("AreCongruent[Segment[(0,1),(1,0)],Segment[(1,0),(0,1)]]", "true");
t("AreCongruent[Segment[(0,1),(1,0)],Segment[(-1,0),(0,-1)]]", "true");
t("AreCongruent[Segment[(0,1),(1,0)],Segment[(2,0),(0,2)]]", "false");
}
@Test
public void cmdIntersect() {
t("Intersect[3x=4y,Curve[5*sin(t),5*cos(t),t,0,6]]", new String[] {
"(4, 3)", "(-4, -3)" },
StringTemplate.editTemplate);
t("Intersect[x=y,x+y=2]", "(1, 1)");
t("Intersect[x=y,x^2+y^2=2]", new String[] { "(1, 1)", "(-1, -1)" });
t("Intersect[x=y,x^2+y^2=2, 1]", "(1, 1)");
t("Intersect[x=y,x^2+y^2=2, (-5, -3)]", "(-1, -1)");
}
@Test
public void cmdNumerator() {
t("Numerator[ (x + 2)/(x+1) ]", "x + 2");
t("Numerator[ 3/7 ]", "3");
t("Numerator[ 5/(-8) ]", "-5");
t("Numerator[ 2/0 ]", "1");
}
@Test
public void cmdDenominator() {
t("Denominator[ (x + 2)/(x+1) ]", "x + 1");
t("Denominator[ 3/7 ]", "7");
t("Denominator[ 5/(-8) ]", "8");
t("Denominator[ 2/0 ]", "0");
}
@Test
public void cmdMaximize() {
t("slider:=Slider[0,5]", "0");
t("Maximize[ 5-(3-slider)^2, slider ]", "3");
t("ptPath:=Point[(x-3)^2+(y-4)^2=25]", "(0, 0)",
StringTemplate.defaultTemplate);
t("Maximize[ y(ptPath), ptPath ]", "(3, 9)",
StringTemplate.defaultTemplate);
}
@Test
public void cmdMinimize() {
t("slider:=Slider[0,5]", "0");
t("Minimize[ 5+(3-slider)^2, slider ]", "3");
t("ptPath:=Point[(x-3)^2+(y-4)^2=25]", "(0, 0)",
StringTemplate.defaultTemplate);
t("Minimize[ y(ptPath), ptPath ]", "(3, -1)",
StringTemplate.defaultTemplate);
}
@Test
public void cmdIteration() {
t("Iteration[ x*2, 2, 5 ]", "64");
t("Iteration[ t*2, t, {(2,3)}, 5 ]", "(64, 96)");
t("Iteration[ x*y, {1,1}, 6 ]", "720");
t("Iteration[ x*y, {1,1}, 0 ]", "1");
t("Iteration[ x*y, {1,1}, -1 ]", "NaN");
}
@Test
public void cmdIterationList() {
t("IterationList[ x*2, 2, 5 ]", "{2, 4, 8, 16, 32, 64}");
t("IterationList[ a+b, a, b, {1,1}, 5 ]", "{1, 1, 2, 3, 5, 8}");
t("IterationList[ x*y, {1,1}, 6 ]", "{1, 1, 2, 6, 24, 120, 720}");
}
@Test
public void cmdImplicitSurface() {
t("ImplicitSurface[sin(x)+sin(y)+sin(z)]",
"sin(x) + sin(y) + sin(z) = 0");
}
@Test
public void cmdSetConstructionStep() {
app.setSaved();
app.clearConstruction();
t("cs=ConstructionStep[]", "1");
t("2", "2");
t("7", "7");
t("SetConstructionStep[2]", new String[] {});
t("cs", "2");
t("SetConstructionStep[1]", new String[] {});
t("cs", "1");
app.clearConstruction();
}
@Test
public void cmdSVD() {
t("SVD[ {{1}} ]", "{{{1}}, {{1}}, {{1}}}");
}
@Test
public void cmdSequence() {
t("Sequence[ 4 ]", "{1, 2, 3, 4}");
t("Sequence[ 3.2, 7.999 ]", "{3, 4, 5, 6, 7, 8}");
t("Sequence[ -3.2, 3.2 ]", "{-3, -2, -1, 0, 1, 2, 3}");
t("Sequence[ 3.2, -2 ]", "{3, 2, 1, 0, -1, -2}");
t("Sequence[ t^2, t, 1, 4 ]", "{1, 4, 9, 16}");
t("Sequence[ t^2, t, 1, 4, 2 ]", "{1, 9}");
t("Sequence[ t^2, t, 1, 4, -2 ]", "{}");
t("Length[Unique[Sequence[ random(), t, 1, 10]]]", "10");
}
@Test
public void cmdOrthogonalPlane() {
t("OrthogonalPlane[ (0,0,1), X=(p,2p,3p) ]", "x + 2y + 3z = 3");
t("OrthogonalPlane[ (0,0,1), Vector[(1,2,3)] ]", "x + 2y + 3z = 3");
}
@Test
public void cmdDifference() {
t("Difference[Polygon[(0,0),(2,0),4],Polygon[(1,1),(3,1),(3,3),(1,3)]]",
new String[] { "3", "(2, 1)", "(1, 1)", "(1, 2)", "(0, 2)",
"(0, 0)", "(2, 0)", "1", "1", "1", "2", "2", "1" },
StringTemplate.defaultTemplate);
t("Difference[Polygon[(0,0),(2,0),4],Polygon[(1,1),(3,1),(3,3),(1,3)], true]",
new String[] { "3", "3", "(3, 3)", "(1, 3)", "(1, 2)",
"(2, 2)", "(2, 1)", "(3, 1)", "(2, 1)", "(1, 1)",
"(1, 2)", "(0, 2)", "(0, 0)", "(2, 0)", "2", "1", "1",
"1", "1", "2", "1", "1", "1", "2", "2", "1" },
StringTemplate.defaultTemplate);
}
@Test
public void parametricSyntaxes() {
t("X=(s,2s)", "X = (0, 0) + s (1, 2)");
t("Intersect[X=(s,s),x+y=2]", "(1, 1)");
}
private static void ti(String in, String out) {
testSyntax(in.replace("i", Unicode.IMAGINARY),
new String[] { out.replace("i", Unicode.IMAGINARY) }, app, ap,
StringTemplate.xmlTemplate);
}
@Test
public void complexArithmetic() {
ti("(0i)^2", "0 + 0i");
ti("(0i)^0", "NaN - NaNi");
ti("(0i)^-1", "NaN - NaNi");
ti("(2+0i)^0", "1 + 0i");
ti("(1/0+0i)^0", "NaN - NaNi");
}
@Test
public void redefine() {
t("la={1}", "{1}");
t("lb={2}", "{2}");
t("lc=la", "{1}");
t("lc=lb", "{2}");
t("1*lb", "{2}");
}
@Test
public void parsePower() {
t("a=4", "4");
t("pia", "12.566370614359172");
t("pix", "(" + Unicode.PI_STRING + " * x)");
t("sinx", "sin(x)");
t("x" + Unicode.PI_STRING, "(" + Unicode.PI_STRING + " * x)");
t("sinxdeg", "sin((1*" + Unicode.DEGREE + " * x))");
}
@Test
public void cmdSum() {
t("listSum={1,10,1/2}", "{1, 10, 0.5}");
t("Sum[ listSum , listSum]", "101.25");
t("Sum[ listSum ]", "11.5");
t("Sum[ listSum , 2 ]", "11");
t("Sum[ listSum , 0 ]", "0");
t("Sum[{x+y,0x+y}]", "x + y + (0 * x) + y");
t("Sum[{x,y}]", "x + y");
t("Sum[{(1,2),(3,4)}]", "(4, 6)");
t("Sum[{(1,2,7),(3,4),(1,1,1)}]", "(5, 7, 8)");
t("Sum[{\"Geo\",\"Gebra\"}]", "GeoGebra");
t("Sum[{}]", "0");
t("Sum[{x+y,2*x}]", "x + y + (2 * x)");
t("Sum[x^k,k,1,5]", "x^(1) + x^(2) + x^(3) + x^(4) + x^(5)");
t("Sum[2^k,k,1,5]", "62");
t("Sum[(k,k),k,1,5]", "(15, 15)");
}
@Test
public void cmdProduct() {
t("Product[ {1,2,3,4} ]", "24");
t("Product[ 1..10, 5 ]", "120");
t("Product[ {1,2,3}, {100,1,2} ]", "18");
t("Product[ k/(k+1),k,1,7 ]", "0.125", StringTemplate.editTemplate);
t("Product[{x,y}]", "(x * y)");
t("Product[ (k,k),k,1,5 ]", "-480 - 480" + Unicode.IMAGINARY);
}
@Test
public void cmdPlane() {
t("Plane[ (0,0,1),(1,0,0),(0,1,0) ]", "x + y + z = 1");
t("Plane[ Polygon[(0,0,1),(2,0,0),(0,3,0)] ]", "3x + 2y + 6z = 6");
t("Plane[ Ellipse[(0,0,1),(2,0,0),(0,3,0)] ]", "3x + 2y + 6z = 6");
t("Plane[ (1,2,3),X=(s,s,s) ]", "x - 2y + z = 0");
t("Plane[ (1,2,3),x+y+z=0 ]", "x + y + z = 6");
t("Plane[ X=(s,s,s+1),X=(s,s,s) ]", "-x + y = 0");
t("Plane[ (0,0,1),Vector[(1,0,0)],Vector[(0,1,0)] ]", "z = 1");
}
@Test
public void cmdSurface() {
t("Surface[u*v,u+v,u^2+v^2,u,-1,1,v,1,3]",
"((u * v), u + v, u^(2) + v^(2))");
t("Surface[2x,2pi]", "(u, ((2 * u) * cos(v)), ((2 * u) * sin(v)))");
t("Surface[2x,2pi,yAxis]",
"((cos(v) * u), ((1 - cos(v) + cos(v)) * (2 * u)), ((-sin(v)) * u))");
}
@Test
public void cmdCube() {
t("Cube[(0,0,0),(0,0,2)]",
new String[] { "8", "(2, 0, 0)", "(0, 2, 0)", "(0, 2, 2)",
"(2, 2, 2)", "(2, 2, 0)", "4", "4", "4", "4", "4", "4",
"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2",
"2" });
t("Cube[(0,0,0),(0,2,0),(0,2,2)]",
new String[] { "8", "(0, 0, 2)", "(2, 0, 0)", "(2, 2, 0)",
"(2, 2, 2)", "(2, 0, 2)", "4", "4", "4", "4", "4", "4",
"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2",
"2" });
t("Cube[(0,0,0),(0,0,2),xAxis]",
new String[] { "8", "(0, -2, 2)", "(0, -2, 0)", "(2, 0, 0)",
"(2, 0, 2)", "(2, -2, 2)", "(2, -2, 0)", "4", "4", "4",
"4", "4", "4", "2", "2", "2", "2", "2", "2", "2", "2",
"2", "2", "2",
"2" });
}
@Test
public void cmdVolume() {
t("Volume[Cube[(0,0,1),(0,1,0)]]", eval("sqrt(8)"),
StringTemplate.editTemplate);
t("Volume[Sphere[(0,0,1),4]]", eval("4/3*pi*4^3"),
StringTemplate.editTemplate);
}
@Test
public void cmdSphere() {
t("Sphere[(0,0,1),4]", indices("x^2 + y^2 + (z - 1)^2 = 16"));
t("Sphere[(0,0,1),(0,4,1)]", indices("x^2 + y^2 + (z - 1)^2 = 16"));
}
@Test
public void cmdCone() {
t("Cone[x^2+y^2=9,4]", new String[] { eval("12*pi"),
"X = (0, 0, 4)",
eval("pi*15"), },
StringTemplate.editTemplate);
t("Cone[(0,0,0),(0,0,4),3]", new String[] { eval("12*pi"),
"X = (0, 0, 0) + (3 cos(t), -3 sin(t), 0)",
eval("pi*15"), },
StringTemplate.editTemplate);
t("Cone[(0,0,0),Vector[(0,0,4)],pi/4]",
new String[] {
indices("x^2 + y^2 - 1z^2 = 0") },
StringTemplate.editTemplate);
}
@Test
public void cmdCylinder() {
t("Cylinder[x^2+y^2=9,4]", new String[] { eval("36*pi"),
"X = (0, 0, 4) + (3 cos(t), 3 sin(t), 0)",
eval("pi*24"), },
StringTemplate.editTemplate);
t("Cylinder[(0,0,0),(0,0,4),3]", new String[] { eval("36*pi"),
"X = (0, 0, 0) + (3 cos(t), -3 sin(t), 0)",
"X = (0, 0, 4) + (3 cos(t), 3 sin(t), 0)",
eval("pi*24") },
StringTemplate.editTemplate);
t("Cylinder[(0,0,0),Vector[(0,0,4)],1]",
new String[] { indices("x^2 + y^2 + 0z^2 = 1") },
StringTemplate.editTemplate);
}
@Test
public void cmdPlaneBisector() {
t("PlaneBisector[(1,1),(1,1,2)]", "z = 1");
t("PlaneBisector[Segment[(1,1),(1,1,2)]]", "z = 1");
}
@Test
public void cmdInfiniteCylinder() {
t("InfiniteCylinder[(1,1),(1,1,2),1]",
indices("x^2 + y^2 + 0z^2 - 2x - 2y = -1"),
StringTemplate.editTemplate);
t("InfiniteCylinder[(1,1),Vector[(0,0,2)],1]",
indices("x^2 + y^2 + 0z^2 - 2x - 2y = -1"),
StringTemplate.editTemplate);
t("InfiniteCylinder[xAxis,1]", indices("y^2 + z^2 = 1"),
StringTemplate.editTemplate);
}
@Test
public void cmdInfiniteCone() {
t("InfiniteCone[(1,1),(1,1,2),45deg]",
indices("x^2 + y^2 - 1z^2 - 2x - 2y = -2"),
StringTemplate.editTemplate);
t("InfiniteCone[(1,1),Vector[(0,0,2)],45deg]",
indices("x^2 + y^2 - 1z^2 - 2x - 2y = -2"),
StringTemplate.editTemplate);
t("InfiniteCone[(1,1),xAxis,45deg]",
indices("-1x^2 + y^2 + z^2 + 2x - 2y = 0"),
StringTemplate.editTemplate);
}
@Test
public void cmdHeight() {
t("Height[Cone[x^2+y^2=9,4]]", "4");
t("Height[Cube[(0,0,1),(0,0,0)]]", "1");
}
@Test
public void cmdEnds() {
t("Ends[Cone[x^2+y^2=9,4]]", new String[] {
"X = (0, 0, 0) + (3 cos(t), -3 sin(t), 0)",
"X = (0, 0, 4)" });
}
@Test
public void cmdBottom() {
t("Bottom[Cone[x^2+y^2=9,4]]",
"X = (0, 0, 0) + (3 cos(t), -3 sin(t), 0)");
}
@Test
public void cmdTop() {
t("Top[Cone[x^2+y^2=9,4]]", "X = (0, 0, 4)");
}
@Test
public void cmdQuadricSide() {
t("Side[Cone[x^2+y^2=9,4]]", eval("15pi"),
StringTemplate.editTemplate);
}
@Test
public void cmdPerpendicularPlane() {
t("PerpendicularPlane[(3,2,7),Line[(1,1,1),(1,1,3)]]", "z = 7");
t("PerpendicularPlane[(3,2,7),Vector[(1,1,0)]]", "x + y = 5");
}
@Test
public void cmdNet() {
t("Net[Cube[(0,0,2),(0,0,0)],1]", new String[] { "24", "(0, 0, 2)",
"(0, 0, 0)", "(2, 0, 0)", "(2, 0, 2)", "(0, 0, 4)",
"(2, 0, 4)", "(2, 0, 6)", "(0, 0, 6)", "(-2, 0, 2)",
"(-2, 0, 0)", "(0, 0, -2)", "(2, 0, -2)", "(4, 0, 0)",
"(4, 0, 2)", "4", "4", "4", "4", "4", "4", "2", "2", "2", "2",
"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2",
"2", "2", "2" },
StringTemplate.editTemplate);
t("Net[Tetrahedron[(0,0,1),(0,1,0),(1,0,0)],Segment[(0,0,1),(0,1,0)]]",
new String[] { "NaN", "(NaN, NaN, NaN)", "(NaN, NaN, NaN)",
"(NaN, NaN, NaN)", "(NaN, NaN, NaN)",
"(NaN, NaN, NaN)", "(NaN, NaN, NaN)", "NaN", "NaN",
"NaN", "NaN",
"NaN", "NaN", "NaN", "NaN", "NaN", "NaN", "NaN", "NaN",
"NaN" });
}
@Test
public void cmdIntersectPath() {
// 3D
t("IntersectPath[x+y+z=1,x+y-z=1]", "X = (1, 0, 0) + " + Unicode.lambda
+ " (-2, 2, 0)");
t("IntersectPath[x^2+y^2+z^2=4,x+y-z=1]",
"X = (0.33333, 0.33333, -0.33333) + (-1.35401 cos(t) - 0.78174 sin(t), 1.35401 cos(t) - 0.78174 sin(t), -1.56347 sin(t))",
StringTemplate.editTemplate);
t("IntersectPath[Polygon[(0,0,0),(2,0,0),(2, 2,0),(0,2,0)],Polygon[(1,1),(3,1),4]]",
new String[] { "1", "(2, 2, 0)", "(1, 2, 0)", "(1, 1, 0)",
"(2, 1, 0)",
"1", "1", "1", "1" },
StringTemplate.editTemplate);
t("IntersectPath[Polygon[(0,0),(2,0),4],x+y=3]", eval("sqrt(2)"),
StringTemplate.editTemplate);
// 2D
t("IntersectPath[Polygon[(0,0,0),(2,0,0),(2, 2,0),(0,2,0)],x+y=3]",
eval("sqrt(2)"),
StringTemplate.editTemplate);
t("IntersectPath[Polygon[(0,0),(2,0),4],Polygon[(1,1),(3,1),4]]",
new String[] { "1", "(2, 2)", "(1, 2)", "(1, 1)", "(2, 1)",
"1", "1", "1", "1" }, StringTemplate.editTemplate);
}
private static String indices(String string) {
return string.replace("^2", Unicode.Superscript_2 + "");
}
private static String eval(String string) {
return ap.evaluateToNumeric(string, true)
.toValueString(StringTemplate.editTemplate);
}
@Test
public void cmdDodecahedron() {
String[] dodeca = new String[] { "7.66312",
"(1.30902, 0.95106, 0)", "(0.5, 1.53884, 0)",
"(-0.30902, -0.42533, 0.85065)",
"(1.30902, -0.42533, 0.85065)", "(1.80902, 1.11352, 0.85065)",
"(0.5, 2.06457, 0.85065)", "(-0.80902, 1.11352, 0.85065)",
"(-0.80902, 0.26287, 1.37638)", "(0.5, -0.68819, 1.37638)",
"(1.80902, 0.26287, 1.37638)", "(1.30902, 1.80171, 1.37638)",
"(-0.30902, 1.80171, 1.37638)", "(-0.30902, 0.42533, 2.22703)",
"(0.5, -0.16246, 2.22703)", "(1.30902, 0.42533, 2.22703)",
"(1, 1.37638, 2.22703)", "(0, 1.37638, 2.22703)", "1.72048",
"1.72048", "1.72048", "1.72048", "1.72048", "1.72048",
"1.72048", "1.72048", "1.72048", "1.72048", "1.72048",
"1.72048", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
"1", "1", "1", "1", "1", "1", "1", "1" };
platonicTest("Dodecahedron", 108, dodeca);
}
private static void platonicTest(String string, int deg, String[] dodeca) {
t(string + "[(1;" + deg + "deg),(0,0)]", dodeca,
StringTemplate.editTemplate);
t(string + "[(1;" + deg + "deg),(0,0),(1,0)]", dodeca,
StringTemplate.editTemplate);
String[] dodeca1 = new String[dodeca.length + 1];
dodeca1[0] = dodeca[0];
dodeca1[1] = "(1, 0, 0)";
for (int i = 2; i < dodeca1.length; i++) {
dodeca1[i] = dodeca[i - 1];
}
t(string + "[(1;" + deg + "deg),(0,0),Vector[(0,0,1)]]", dodeca1,
StringTemplate.editTemplate);
}
@Test
public void cmdIcosahedron() {
String[] dodeca = new String[] { "2.18169",
"(-0.30902, 0.75576, 0.57735)", "(0.5, -0.6455, 0.57735)",
"(1.30902, 0.75576, 0.57735)", "(0.5, 1.22285, 0.93417)",
"(-0.30902, -0.17841, 0.93417)",
"(1.30902, -0.17841, 0.93417)", "(0, 0.57735, 1.51152)",
"(0.5, -0.28868, 1.51152)", "(1, 0.57735, 1.51152)", "0.43301",
"0.43301", "0.43301", "0.43301", "0.43301", "0.43301",
"0.43301", "0.43301", "0.43301", "0.43301", "0.43301",
"0.43301", "0.43301", "0.43301", "0.43301", "0.43301",
"0.43301", "0.43301", "0.43301", "0.43301", "1", "1", "1", "1",
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
"1", "1" };
platonicTest("Icosahedron", 60, dodeca);
}
@Test
public void cmdOctahedron() {
String[] dodeca = new String[] { "0.4714", "(0, 0.57735, 0.8165)",
"(0.5, -0.28868, 0.8165)", "(1, 0.57735, 0.8165)", "0.43301",
"0.43301", "0.43301", "0.43301", "0.43301", "0.43301",
"0.43301", "0.43301", "1", "1", "1", "1", "1", "1", "1", "1",
"1", "1", "1", "1" };
platonicTest("Octahedron", 60, dodeca);
}
@Test
public void cmdPyramid() {
t("Pyramid[(0,0,0),(1,0,0),(0,1,0),(0,0,1)]", new String[] {
eval("1/6"), "0.5", "0.5", eval("sqrt(3)/2"), "0.5", "1",
eval("sqrt(2)"), "1", "1", eval("sqrt(2)"), eval("sqrt(2)"),
},
StringTemplate.editTemplate);
t("Pyramid[Polygon[(0,0,0),(1,0,0),(0,1,0)],(0,0,1)]", new String[] {
eval("1/6"), "0.5", eval("sqrt(3)/2"), "0.5", "1",
eval("sqrt(2)"), eval("sqrt(2)"),
},
StringTemplate.editTemplate);
t("Pyramid[Polygon[(-3,0,0),(0,-3,0),(3,0,0),(0,3,0)],4]",
new String[] {
"24", "(0, 0, 4)", "9.60469", "9.60469",
"9.60469", "9.60469", "5", "5", "5", "5" },
StringTemplate.editTemplate);
}
@Test
public void cmdPrism() {
t("Prism[(0,0,0),(1,0,0),(0,1,0),(0,0,1)]", new String[] { "0.5",
"(1, 0, 1)", "(0, 1, 1)", "0.5", "1", eval("sqrt(2)"), "1",
"0.5", "1", eval("sqrt(2)"), "1", "1", "1", "1", "1",
eval("sqrt(2)"), "1" },
StringTemplate.editTemplate);
t("Prism[Polygon[(0,0,0),(1,0,0),(0,1,0)],(0,0,1)]", new String[] {
"0.5", "(1, 0, 1)", "(0, 1, 1)", "1", eval("sqrt(2)"), "1",
"0.5", "1", "1", "1", "1", eval("sqrt(2)"), "1" },
StringTemplate.editTemplate);
t("Prism[Polygon[(-3,0,0),(0,-3,0),(3,0,0),(0,3,0)],4]", new String[] {
"72", "(-3, 0, 4)", "(0, -3, 4)", "(3, 0, 4)", "(0, 3, 4)",
eval("12sqrt(2)"), eval("12sqrt(2)"), eval("12sqrt(2)"),
eval("12sqrt(2)"), "18", "4", "4",
"4", "4", eval("3sqrt(2)"),
eval("3sqrt(2)"),
eval("3sqrt(2)"), eval("3sqrt(2)") },
StringTemplate.editTemplate);
}
@Test
public void cmdTetrahedron() {
String[] dodeca = new String[] { "0.11785", "(0.5, 0.28868, 0.8165)",
"0.43301", "0.43301", "0.43301", "0.43301", "1", "1", "1", "1",
"1", "1" };
platonicTest("Tetrahedron", 60, dodeca);
}
@Test
public void cmdOrthogonalLine() {
// 2D
t("PerpendicularLine[ (1,2), x+y=7 ]", "-x + y = 1");
t("PerpendicularLine[ (1,2), Segment[(1,6),(6,1)] ]", "-x + y = 1");
t("PerpendicularLine[ (1,2),Vector[(1,3)]]", "-x - 3y = -7");
// 3D
t("PerpendicularLine[ (1,2,0), x+y=7 ]", "X = (1, 2, 0) + "
+ Unicode.lambda + " (1, 1, 0)");
t("PerpendicularLine[ (1,2,0), Segment[(1,6),(6,1)] ]",
"X = (1, 2, 0) + " + Unicode.lambda + " (-5, -5, 0)");
t("PerpendicularLine[ (1,2,0),Vector[(1,3)]]", "X = (1, 2, 0) + "
+ Unicode.lambda + " (3, -1, 0)");
t("PerpendicularLine[(1,1,1),z=0]", "X = (1, 1, 1) + " + Unicode.lambda
+ " (0, 0, -1)");
t("PerpendicularLine[(1,1,1),y=0,xOyPlane]", "X = (1, 1, 1) + "
+ Unicode.lambda + " (0, 1, 0)");
t("PerpendicularLine[(1,1,1),y=0,space]", "X = (1, 1, 1) + "
+ Unicode.lambda + " (0, 0.70711, 0.70711)",
StringTemplate.editTemplate);
t("PerpendicularLine[x=1,y=1]", "X = (1, 1, 0) + " + Unicode.lambda
+ " (0, 0, 1)");
}
@Test
public void testExpIntegral() {
t("expIntegral(5)", "40.18528", StringTemplate.editTemplate);
t("expIntegral(5+0i)", "40.18528 + 0" + Unicode.IMAGINARY,
StringTemplate.editTemplate);
}
@Test
public void testInverseTrigDegree(){
t("asind(0.5)", "30\u00B0", StringTemplate.editTemplate);
t("acosd(0.5)", "60\u00B0", StringTemplate.editTemplate);
t("atand(1)", "45\u00B0", StringTemplate.editTemplate);
t("asind(0.317)", "18.48159\u00B0", StringTemplate.editTemplate);
t("acosd(0.317)", "71.51841\u00B0", StringTemplate.editTemplate);
t("atand(0.317)", "17.58862\u00B0", StringTemplate.editTemplate);
}
@Test
public void cmdSpline() {
String theSpline = "(If[t < 0.38743, 0.88246t^3 + 0t^2 + 2.44868t, t < 1, -0.55811t^3 + 1.67434t^2 + 1.8t + 0.08377], If[t < 0.38743, -5.43794t^3 + 0t^2 + 3.39737t, t < 1, 3.43925t^3 - 10.31776t^2 + 7.39473t - 0.51623])";
t("Spline[{(0,0),(1,1),(3,0)}]", unicode(theSpline),
StringTemplate.editTemplate);
t("Spline[{(0,0),(1,1),(3,0)},3]", unicode(theSpline),
StringTemplate.editTemplate);
t("Spline[{(0,0),(1,1),(3,0)},3,sqrt(x^2+y^2)]",
unicode(theSpline),
StringTemplate.editTemplate);
t("Spline[{(0,0),(1,1),(1,1),(3,0)},4]", "?",
StringTemplate.editTemplate);
}
@Test
public void cmdPolynomial() {
t("Polynomial[ sin(x) ]", "?");
t("Polynomial[ 1*x^2-1*x+1 ]", "x^(2) - x + 1");
t("Polynomial[ -x*(x+1)*(x-1) ]", "(-x^(3)) + x");
t("Polynomial[ (2x+3)^3 ]",
"(8 * x^(3)) + (36 * x^(2)) + (54 * x) + 27");
t("Polynomial[ {(1,1),(-1,1),(0,0) } ]", "x^(2)");
t("Polynomial[ {(1,0),(-1,2),(0,0) } ]", "x^(2) - x");
}
@Test
public void cmdRandomPolynomial() {
app.setRandomSeed(42);
t("RandomPolynomial[5,-1,1]", "x^(5) - x^(4) + x^(3) - x^(2) - x + 1");
t("RandomPolynomial[5,-1,1]", "(-x^(5)) + x^(4) + x^(3) + x + 1");
t("RandomPolynomial[5,-1,1]", "x^(5) - x^(4) + x^(3) + x^(2) - x - 1");
t("RandomPolynomial[5,-1,1]", "(-x^(5)) + x^(4) + x^(2) + x");
t("RandomPolynomial[5,-1,1]", "(-x^(5)) - x + 1");
t("RandomPolynomial[5,-1,1]", "(-x^(5)) + x^(4) + x^(3) + x^(2) - x");
t("RandomPolynomial[5,-1,1]", "x^(5) + x^(4) - x^(3) - 1");
t("RandomPolynomial[5,-2,2]",
"(2 * x^(5)) + (2 * x^(3)) - (2 * x^(2)) + 1");
t("RandomPolynomial[5,-3,3]",
"(2 * x^(5)) - x^(4) - (3 * x^(3)) + (2 * x^(2)) + 3");
t("RandomPolynomial[5,-5,4]",
"(-5 * x^(5)) - (4 * x^(4)) + (4 * x^(3)) - (2 * x^(2)) - (5 * x) - 5");
t("RandomPolynomial[5,-2,5]",
"x^(5) + (5 * x^(4)) - x^(3) + (4 * x) + 1");
}
@Test
public void testIndexLookup() {
t("aa_{1}=1", "1");
t("aa_{1}+1", "2");
t("aa_1+1", "2");
t("ab_1=1", "1");
t("ab_{1}+1", "2");
t("ab_1+1", "2");
// overwrite
t("ab_1=3", "3");
t("ab_{1}+1", "4");
}
@Test
public void cmdUnion() {
t("join=Union[Polygon[(1,1),(1,0),(0,1)],Polygon[(0,0),(1,0),(0,1)]]",
new String[] { "1", "(1, 0)", "(1, 1)", "(0, 1)", "(0, 0)", "1",
"1", "1", "1" });
t("join=Union[Polygon[(1,1,0),(1,0,0),(0,1,0)],Polygon[(0,0,0),(1,0,0),(0,1,0)]]",
new String[] { "1", "(1, 0, 0)", "(0, 0, 0)", "(0, 1, 0)",
"(1, 1, 0)", "1", "1", "1", "1" });
t("Union[{1,2,3}, {2,2,2,4,4,4}]", "{1, 2, 3, 4}");
t("Union[{\"1\",\"2\",\"3\"}, {\"2\",\"2\",\"2\",\"4\",\"4\",\"4\"}]",
"{\"1\", \"2\", \"3\", \"4\"}");
}
@Test
public void cmdInvert() {
t("Invert[ {{1,1},{0,2}} ]", "{{1, -0.5}, {0, 0.5}}");
t("Invert[ sin(x) ]", "asin(x)");
app.getSettings().getCasSettings().setEnabled(false);
app.getKernel().getAlgebraProcessor().reinitCommands();
t("Invert[ sin(x) ]", "NInvert[sin(x)]");
app.getSettings().getCasSettings().setEnabled(true);
}
@Test
public void cmdNInvert() {
t("ni(x)=Invert[ sin(x) ]", "NInvert[sin(x)]");
t("ni(sin(1))", "1");
}
@Test
public void testShorthandIntersect() {
t("x=2*y=3*z", "X = (0, 0, 0) + " + Unicode.lambda + " (6, 3, 2)");
t("(x=2y,2y=3z)", "X = (0, 0, 0) + " + Unicode.lambda + " (6, 3, 2)");
t("x-1=y+2=z-6",
"X = (-2.3333333333333335, -5.333333333333333, 2.6666666666666665) + "
+ Unicode.lambda + " (1, 1, 1)");
t("(x-1)/3=(y+2)/2=5(z-6)",
"X = (-60.47239263803682, -42.981595092024556, 1.9018404907975464) + "
+ Unicode.lambda
+ " (2.5, 1.6666666666666665, 0.16666666666666666)");
t("1-x=y+2=z-6",
"X = (4.333333333333334, -5.333333333333333, 2.6666666666666665) + "
+ Unicode.lambda + " (1, -1, -1)");
t("x+x-1=y+y+2=z-6+z",
"X = (-1.1666666666666667, -2.6666666666666665, 1.3333333333333333) + "
+ Unicode.lambda + " (4, 4, 4)");
}
@Test
public void cmdFit() {
t("Fit[ {(0,1),(1,2),(2,5)}, {x^2,x,1} ]", unicode("1x^2 + 0x + 1 (1)"),
StringTemplate.editTemplate);
t("Fit[ {(0,1,1),(1,1,2),(2,1,5),(0,2,4),(1,2,5),(2,2,8)}, {x^2,x,1,x^2*y,x*y,y} ]",
unicode("3y + 0x y + 0x^2 y - 2 + 0x + 1x^2"),
StringTemplate.editTemplate);
t("a=Slider[0,10]", "0");
t("b=Slider[0,10]", "0");
t("c=Slider[0,10]", "0");
t("Fit[ {(0,1),(1,2),(2,5)},a*x^2+b*x+c ]",
unicode("1x^2 + 0x + 1"),
StringTemplate.editTemplate);
}
@Test
public void zipReloadTest() {
t("list1=Zip[f(1),f,{x,x+1}]", "{1, 2}");
String xml = app.getGgbApi().getXML();
t("list2=Zip[f(1,2),f,{x+y,y+x+1}]", "{3, 4}");
app.getKernel().clearConstruction(true);
app.getGgbApi().setXML(xml);
t("list1", "{1, 2}");
t("Object[\"list2\"]", "NaN");
}
private static String unicode(String theSpline) {
return theSpline.replace("^2", Unicode.Superscript_2 + "").replace("^3",
Unicode.Superscript_3 + "");
}
}