Skip to content

Commit

Permalink
#27 Calculator: add trigonometric functions
Browse files Browse the repository at this point in the history
  • Loading branch information
greipadmin committed Apr 5, 2019
1 parent a73a32f commit 3b44181
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 15 deletions.
2 changes: 1 addition & 1 deletion org.greip/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="lib" path="lib/exp4j-0.4.8.jar"/>
<classpathentry exported="true" kind="lib" path="lib/exp4j-0.4.8.jar" sourcepath="lib/exp4j-0.4.8-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
Expand Down
150 changes: 138 additions & 12 deletions org.greip/src/org/greip/calculator/CalcualtionEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
import org.eclipse.swt.SWT;
import org.greip.common.Util;

import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import net.objecthunter.exp4j.function.Function;

class CalcualtionEngine {

private static final String IGNORE = String.valueOf((char) 0);

static final char NEGATE = '\u02D7';
static final char SIGN = '\u00B1';
static final char DIVIDE = '\u00F7';
Expand All @@ -33,7 +35,38 @@ class CalcualtionEngine {
static final char M_PLUS = '\u0004';
static final char M_MINUS = '\u0005';

private static final String OPERATORS = "+-%/*";
static final char SIN = '\uFFFF';
static final char COS = '\uFFFE';
static final char TAN = '\uFFFD';
static final char SINH = '\uFFFC';
static final char COSH = '\uFFFB';
static final char TANH = '\uFFFA';

static final char SQRT = '\uFFEF';
static final char CBRT = '\uFFEE';
static final char POW = '\uFFED';

static final char LN = '\uFFCF';
static final char LOG = '\uFFCE';
static final char EXP = '\uFFCD';

static final char PI = '\u03C0';
static final char E = '\u2107';

private static final String OPERATORS = "+-%/*^";

private static final Function FSIN = new Func("sin", args -> Math.sin(Math.toRadians(args[0])));
private static final Function FCOS = new Func("cos", args -> Math.cos(Math.toRadians(args[0])));
private static final Function FTAN = new Func("tan", args -> Math.tan(Math.toRadians(args[0])));
private static final Function FSINH = new Func("sinh", args -> Math.sinh(args[0]));
private static final Function FCOSH = new Func("cosh", args -> Math.cosh(args[0]));
private static final Function FTANH = new Func("tanh", args -> Math.tanh(args[0]));
private static final Function FCBRT = new Func("cbrt", args -> Math.cbrt(args[0]));
private static final Function FSQRT = new Func("sqrt", args -> Math.sqrt(args[0]));
private static final Function FPOW = new Func("pow", args -> Math.pow(args[0], 2d));
private static final Function FLN = new Func("ln", args -> Math.log(args[0]));
private static final Function FLOG = new Func("log", args -> Math.log10(args[0]));
private static final Function FEXP = new Func("exp", args -> Math.exp(args[0]));

static class CalculationResult {

Expand All @@ -54,6 +87,26 @@ public String getResult() {
}
}

@FunctionalInterface
interface Intrinsic {
double calculate(double... values);
}

static class Func extends Function {

private final Intrinsic intrinsic;

Func(final String name, final Intrinsic function) {
super(name);
this.intrinsic = function;
}

@Override
public double apply(final double... values) {
return intrinsic.calculate(values);
}
}

private final StringBuilder formula = new StringBuilder();
private BigDecimal memory;

Expand Down Expand Up @@ -106,10 +159,10 @@ private BigDecimal calculateFormula() {
index++;
}

final ExpressionBuilder e = new ExpressionBuilder(expression.substring(index));
final Expression build = e.build();
final ExpressionBuilder eb = new ExpressionBuilder(expression.substring(index));
eb.functions(FSIN, FCOS, FTAN, FSINH, FCOSH, FTANH, FSQRT, FCBRT, FPOW);

return new BigDecimal(build.evaluate());
return new BigDecimal(eb.build().evaluate());
}

private BigDecimal toBigDecimal(final String token) throws ParseException {
Expand All @@ -130,6 +183,7 @@ public void process(final char... commands) throws CalculationException {
}

} catch (final Exception e) {
e.printStackTrace();
resetTo(BigDecimal.ZERO);
throw e instanceof CalculationException ? (CalculationException) e : new CalculationException(e);
}
Expand All @@ -147,10 +201,6 @@ public CalculationResult getCalculationResult() {

private void processCommand(final char command) throws Exception {

if (!isLegalCommand(command)) {
throw new IllegalArgumentException("unknown command " + command);
}

if (command == decimalSeparator) {
if (!lastCharIs(')')) {
if (!isNumberEntered) {
Expand Down Expand Up @@ -225,6 +275,7 @@ private void processCommand(final char command) throws Exception {
case '-':
case '*':
case '/':
case '^':
if (isNumberEntered || formula.length() == 0) {
formula.append(getCurrentValueAsString());
calculate();
Expand All @@ -236,6 +287,55 @@ private void processCommand(final char command) throws Exception {
lastOperation = String.valueOf(command);
break;

case SIN:
executeFunction(FSIN);
break;
case COS:
executeFunction(FCOS);
break;
case TAN:
executeFunction(FTAN);
break;

case SINH:
executeFunction(FSINH);
break;
case COSH:
executeFunction(FCOSH);
break;
case TANH:
executeFunction(FTANH);
break;

case SQRT:
executeFunction(FSQRT);
break;
case CBRT:
executeFunction(FCBRT);
break;

case POW:
executeFunction(FPOW);
break;

case LN:
executeFunction(FLN);
break;
case LOG:
executeFunction(FLOG);
break;
case EXP:
executeFunction(FEXP);
break;

case PI:
applyConstant(Math.PI);
break;

case E:
applyConstant(Math.E);
break;

case 'C':
resetTo(BigDecimal.ZERO);
break;
Expand Down Expand Up @@ -270,7 +370,11 @@ private void processCommand(final char command) throws Exception {
break;

default:
if (!lastCharIs(')')) {
if (IGNORE.equals(lastOperation)) {
lastOperation = null;
result = String.valueOf(command);
formula.setLength(0);
} else if (!lastCharIs(')')) {
if (!isNumberEntered) {
result = "";
if (!lastCharIsOperator()) {
Expand All @@ -286,7 +390,28 @@ private void processCommand(final char command) throws Exception {
lastOperation = null;
}

isNumberEntered = command == SIGN || Character.isDigit(command);
isNumberEntered = Character.isDigit(command) || Util.in(command, SIGN, PI, E);
}

private void applyConstant(final double constant) {
if (!lastCharIsOperator() || lastCharIs(')')) {
formula.setLength(0);
}
result = getDecimalFormat().format(constant);
}

private void executeFunction(final Function function) throws ParseException {
if (isNumberEntered || formula.length() == 0) {
formula.append(function.getName()).append('(');
formula.append(getCurrentValueAsString());
formula.append(')');
result = getDecimalFormat().format(function.apply(getCurrentValue().doubleValue()));
// } else {
// formula.insert(0, function.getName() + '(');
// formula.append(')');
// result = getDecimalFormat().format(function.apply(getCurrentValue().doubleValue()));
}
lastOperation = IGNORE;
}

private void closeAllParentheses() {
Expand Down Expand Up @@ -356,7 +481,8 @@ private boolean lastCharIs(final char ch) {
}

public boolean isLegalCommand(final char command) {
return (OPERATORS + "0123456789=CE()" + SIGN + SWT.BS).indexOf(normalizeCommand(command)) != -1 || command == decimalSeparator;
return (OPERATORS + SIN + COS + TAN + SINH + COSH + TANH + "0123456789=CE()" + SIGN + SWT.BS).indexOf(normalizeCommand(command)) != -1
|| command == decimalSeparator;
}

private static boolean isMemoryCommand(final char command) {
Expand Down
56 changes: 54 additions & 2 deletions org.greip/src/org/greip/calculator/Calculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
Expand Down Expand Up @@ -95,6 +96,11 @@ public static void execute(final Event e, final Calculator calculator) {

private Label lblMemory;

private final Color fnBackground;
private final Font fnFont;

private final boolean simple;

/**
* Constructs a new instance of this class given its parent.
*
Expand All @@ -109,13 +115,27 @@ public static void execute(final Event e, final Calculator calculator) {
* </ul>
*/
public Calculator(final Composite parent) {
this(parent, SWT.NONE);
}

public Calculator(final Composite parent, final int style) {
super(parent, SWT.NONE);

simple = style == SWT.SIMPLE;

setLayout(GridLayoutFactory.fillDefaults().margins(5, 5).spacing(2, 2).numColumns(5).create());
setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
setBackgroundMode(SWT.INHERIT_FORCE);
addListener(SWT.Resize, e -> showFormula());

fnFont = new Font(getDisplay(), "Calibri", 8, SWT.ITALIC);
fnBackground = new Color(getDisplay(), 100, 100, 200);

addListener(SWT.Dispose, e -> {
fnBackground.dispose();
fnFont.dispose();
});

createFocusControl();
createResultPanel();
createButtons();
Expand Down Expand Up @@ -175,6 +195,28 @@ private void createButtons() {
createSmallButton("(", '(', 3, SWT.COLOR_BLACK);
createSmallButton(")", ')', 0, SWT.COLOR_BLACK);

if (!simple) {
createSpacer();

createFnButton("sin", CalcualtionEngine.SIN, 0);
createFnButton("cos", CalcualtionEngine.COS, 0);
createFnButton("tan", CalcualtionEngine.TAN, 0);
createFnButton("\u221A", CalcualtionEngine.SQRT, 3);
createFnButton(\u221A", CalcualtionEngine.CBRT, 0);

createFnButton("sinh", CalcualtionEngine.SINH, 0);
createFnButton("cosh", CalcualtionEngine.COSH, 0);
createFnButton("tanh", CalcualtionEngine.TANH, 0);
createFnButton("x²", CalcualtionEngine.POW, 3);
createFnButton("x^y", '^', 0);

createFnButton("ln", CalcualtionEngine.LN, 0);
createFnButton("log", CalcualtionEngine.LOG, 0);
createFnButton("e\u02E3", CalcualtionEngine.EXP, 0);
createFnButton("\u03C0", CalcualtionEngine.PI, 3);
createFnButton("\u2107", CalcualtionEngine.E, 0);
}

createSpacer();

createButtonsFor('7', '8', '9', SPACER, CalcualtionEngine.DIVIDE, '%');
Expand Down Expand Up @@ -206,7 +248,7 @@ private void createButtonsFor(final char... actions) {
private void createButton(final char action, final int hSpan, final int vSpan, final int indent) {
final Button btn = createButton(String.valueOf(action), action);
btn.setLayoutData(
GridDataFactory.fillDefaults().span(hSpan, vSpan).grab(true, true).minSize(30, SWT.DEFAULT).indent(indent, 0).create());
GridDataFactory.fillDefaults().span(hSpan, vSpan).grab(true, true).minSize(33, SWT.DEFAULT).indent(indent, 0).create());
}

private Button createButton(final String text, final char action) {
Expand All @@ -219,12 +261,22 @@ private Button createButton(final String text, final char action) {
return btn;
}

private void createFnButton(final String text, final char action, final int hIndent) {
final FnButton btn = new FnButton(this, text, fnBackground);

btn.setFont(fnFont);
btn.setLayoutData(
GridDataFactory.fillDefaults().grab(true, false).minSize(33, SWT.DEFAULT).hint(SWT.DEFAULT, 20).indent(hIndent, 0).create());

btn.addListener(SWT.MouseDown, e -> processAction(action));
}

private Button createSmallButton(final String text, final char action, final int hIndent, final int color) {
final Button btn = createButton("", action);

btn.setForeground(getDisplay().getSystemColor(color));
btn.setLayoutData(
GridDataFactory.fillDefaults().grab(true, true).minSize(30, SWT.DEFAULT).hint(SWT.DEFAULT, 19).indent(hIndent, 0).create());
GridDataFactory.fillDefaults().grab(true, true).minSize(33, SWT.DEFAULT).hint(SWT.DEFAULT, 19).indent(hIndent, 0).create());

Util.applyDerivedFont(btn, -3, SWT.NONE);

Expand Down
Loading

0 comments on commit 3b44181

Please sign in to comment.