Added new expression blocks, like parentheses and power of x

This commit is contained in:
XDrake99 2017-04-11 22:04:44 +02:00
parent c2df21d682
commit 57fc8cfa44
12 changed files with 424 additions and 76 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

View File

@ -11,29 +11,34 @@ public class BlockContainer implements GraphicalElement {
private static boolean initialized = false;
private final int minWidth;
private final int minHeight;
private int minWidth;
private int minHeight;
private final ObjectArrayList<Block> content;
private boolean small;
private int width;
private int height;
private int line;
public final boolean withBorder;
private boolean autoMinimums;
public BlockContainer() {
this(false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true);
autoMinimums = true;
}
public BlockContainer(boolean small) {
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), true);
autoMinimums = true;
}
public BlockContainer(boolean small, boolean withBorder) {
this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), withBorder);
autoMinimums = true;
}
public BlockContainer(boolean small, int minWidth, int minHeight, boolean withBorder) {
this(small, minWidth, minHeight, new ObjectArrayList<>(), withBorder);
autoMinimums = false;
}
public BlockContainer(boolean small, int minWidth, int minHeight, ObjectArrayList<Block> content, boolean withBorder) {
@ -111,9 +116,9 @@ public class BlockContainer implements GraphicalElement {
if (caret.getRemaining() == 0) {
if (content.size() > 0) {
BlockContainer.drawCaret(ge, r, caret, x, y + line - content.get(0).line, content.get(0).height);
BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height);
} else {
BlockContainer.drawCaret(ge, r, caret, x, y, height);
BlockContainer.drawCaret(ge, r, caret, small, x, y, height);
}
}
@ -128,7 +133,7 @@ public class BlockContainer implements GraphicalElement {
b.draw(ge, r, x + paddingX, y + line - b.line, caret);
paddingX += b.getWidth();
if (caret.getRemaining() == 0) {
BlockContainer.drawCaret(ge, r, caret, x + paddingX, y + line - b.line, b.height);
BlockContainer.drawCaret(ge, r, caret, small, x + paddingX, y + line - b.line, b.height);
}
paddingX += 1;
}
@ -271,17 +276,22 @@ public class BlockContainer implements GraphicalElement {
return defFontSizes[b ? 3 : 1];
}
public static void drawCaret(GraphicEngine ge, Renderer r, Caret caret, int x, int y, int height) {
public static void drawCaret(GraphicEngine ge, Renderer r, Caret caret, boolean small, int x, int y, int height) {
if (caret.getState() == CaretState.VISIBLE_ON) {
r.glColor(getDefaultColor());
r.glDrawLine(x, y, x, y - 1 + height);
r.glDrawLine(x + 1, y, x + 1, y - 1 + height);
r.glDrawLine(x + 2, y, x + 2, y - 1 + height);
r.glFillColor(x, y, small?2:3, height);
}
}
public void setSmall(boolean small) {
this.small = small;
if (this.autoMinimums) {
this.minWidth = BlockContainer.getDefaultCharWidth(small);
this.minHeight = BlockContainer.getDefaultCharHeight(small);
}
for (Block b : this.content) {
b.setSmall(small);
}
recomputeDimensions();
}

View File

@ -0,0 +1,8 @@
package org.warp.picalculator.gui.expression;
public class BlockExponentialNotation extends BlockPower {
@Override
protected int getSpacing() {
return -3;
}
}

View File

@ -1,5 +1,6 @@
package org.warp.picalculator.gui.expression;
import org.warp.picalculator.gui.graphicengine.BinaryFont;
import org.warp.picalculator.gui.graphicengine.GraphicEngine;
import org.warp.picalculator.gui.graphicengine.Renderer;
@ -9,6 +10,9 @@ public class BlockParenthesis extends Block {
private final BlockContainer containerNumber;
private int chw;
private int chh;
public BlockParenthesis() {
containerNumber = new BlockContainer(false);
recomputeDimensions();
@ -18,7 +22,13 @@ public class BlockParenthesis extends Block {
public void draw(GraphicEngine ge, Renderer r, int x, int y, Caret caret) {
BlockContainer.getDefaultFont(small).use(ge);
r.glColor(BlockContainer.getDefaultColor());
containerNumber.draw(ge, r, x + 7, y + 3, caret);
r.glDrawCharLeft(x, y, '╭');
r.glDrawCharLeft(x, y+height-chh, '╰');
r.glFillColor(x+3, y+6, 2, height-6*2);
r.glFillColor(x+width-5, y+6, 2, height-6*2);
r.glDrawCharLeft(x+width-chw, y, '╮');
r.glDrawCharLeft(x+width-chw, y+height-chh, '╯');
containerNumber.draw(ge, r, x+chw, y, caret);
}
@Override
@ -43,7 +53,9 @@ public class BlockParenthesis extends Block {
@Override
public void recomputeDimensions() {
width = containerNumber.getWidth() + BlockContainer.getDefaultCharWidth(small) * 2;
chw = BlockContainer.getDefaultCharWidth(small);
chh = BlockContainer.getDefaultCharHeight(small);
width = containerNumber.getWidth() + chw * 2 + 3;
height = containerNumber.getHeight();
line = containerNumber.getLine();
}

View File

@ -0,0 +1,97 @@
package org.warp.picalculator.gui.expression;
import org.warp.picalculator.gui.expression.Block;
import org.warp.picalculator.gui.expression.BlockContainer;
import org.warp.picalculator.gui.expression.Caret;
import org.warp.picalculator.gui.graphicengine.GraphicEngine;
import org.warp.picalculator.gui.graphicengine.Renderer;
public class BlockPower extends Block {
public static final int CLASS_ID = 0x00000005;
private final BlockContainer containerNumber;
private final BlockContainer containerExponent;
private int h1;
private int w1;
public BlockPower() {
containerNumber = new BlockContainer(false);
containerExponent = new BlockContainer(true);
recomputeDimensions();
}
@Override
public void draw(GraphicEngine ge, Renderer r, int x, int y, Caret caret) {
BlockContainer.getDefaultFont(small).use(ge);
r.glColor(BlockContainer.getDefaultColor());
containerNumber.draw(ge, r, x, y+height-h1, caret);
BlockContainer.getDefaultFont(true).use(ge);
containerExponent.draw(ge, r, x+w1+getSpacing(), y, caret);
}
@Override
public boolean putBlock(Caret caret, Block newBlock) {
boolean added = false;
added = added | containerNumber.putBlock(caret, newBlock);
added = added | containerExponent.putBlock(caret, newBlock);
if (added) {
recomputeDimensions();
}
return added;
}
@Override
public boolean delBlock(Caret caret) {
boolean removed = false;
removed = removed | containerNumber.delBlock(caret);
removed = removed | containerExponent.delBlock(caret);
if (removed) {
recomputeDimensions();
}
return removed;
}
@Override
public void recomputeDimensions() {
w1 = containerNumber.getWidth();
final int w2 = containerExponent.getWidth();
h1 = containerNumber.getHeight();
final int h2 = containerExponent.getHeight();
final int l1 = containerNumber.getLine();
width = w1+getSpacing()+1+w2;
height = h1 + h2 - 3;
line = height-h1+l1;
}
@Override
public void setSmall(boolean small) {
this.small = small;
containerNumber.setSmall(small);
containerExponent.setSmall(true);
recomputeDimensions();
}
public BlockContainer getNumberContainer() {
return containerNumber;
}
public BlockContainer getExponentContainer() {
return containerExponent;
}
@Override
public int getClassID() {
return CLASS_ID;
}
@Override
public int computeCaretMaxBound() {
return containerNumber.computeCaretMaxBound() + containerExponent.computeCaretMaxBound();
}
protected int getSpacing() {
return 1;
}
}

View File

@ -74,6 +74,8 @@ public abstract class InputContainer implements GraphicalElement, InputLayout, S
final int curPos = caret.getPosition();
if (curPos > 0) {
caret.setPosition(curPos - 1);
} else {
caret.setPosition(maxPosition-1);
}
caret.turnOn();
caretTime = 0;
@ -83,6 +85,8 @@ public abstract class InputContainer implements GraphicalElement, InputLayout, S
final int curPos = caret.getPosition();
if (curPos + 1 < maxPosition) {
caret.setPosition(curPos + 1);
} else {
caret.setPosition(0);
}
caret.turnOn();
caretTime = 0;

View File

@ -4,6 +4,7 @@ import org.warp.picalculator.gui.expression.Block;
import org.warp.picalculator.gui.expression.BlockChar;
import org.warp.picalculator.gui.expression.BlockDivision;
import org.warp.picalculator.gui.expression.BlockParenthesis;
import org.warp.picalculator.gui.expression.BlockPower;
import org.warp.picalculator.gui.expression.BlockSquareRoot;
import org.warp.picalculator.math.MathematicalSymbols;
@ -29,8 +30,12 @@ public class NormalInputContainer extends InputContainer {
case MathematicalSymbols.SQUARE_ROOT:
return new BlockSquareRoot();
case MathematicalSymbols.PARENTHESIS_OPEN:
case MathematicalSymbols.PARENTHESIS_CLOSE:
return new BlockParenthesis();
case MathematicalSymbols.PARENTHESIS_CLOSE:
return null;
case MathematicalSymbols.POWER:
case MathematicalSymbols.POWER_OF_TWO:
return new BlockPower();
case MathematicalSymbols.MULTIPLICATION:
case MathematicalSymbols.SUM:
case MathematicalSymbols.SUM_SUBTRACTION:
@ -50,4 +55,12 @@ public class NormalInputContainer extends InputContainer {
return new BlockChar(c);
}
}
@Override
public void typeChar(char c) {
super.typeChar(c);
if (c == MathematicalSymbols.PARENTHESIS_CLOSE) {
this.moveRight();
}
}
}

View File

@ -10,6 +10,10 @@ import org.warp.picalculator.gui.expression.Block;
import org.warp.picalculator.gui.expression.BlockChar;
import org.warp.picalculator.gui.expression.BlockContainer;
import org.warp.picalculator.gui.expression.BlockDivision;
import org.warp.picalculator.gui.expression.BlockExponentialNotation;
import org.warp.picalculator.gui.expression.BlockParenthesis;
import org.warp.picalculator.gui.expression.BlockPower;
import org.warp.picalculator.gui.expression.BlockSquareRoot;
import org.warp.picalculator.gui.expression.containers.InputContainer;
import org.warp.picalculator.math.Function;
import org.warp.picalculator.math.FunctionOperator;
@ -17,6 +21,8 @@ import org.warp.picalculator.math.FunctionSingle;
import org.warp.picalculator.math.MathContext;
import org.warp.picalculator.math.MathematicalSymbols;
import org.warp.picalculator.math.functions.Number;
import org.warp.picalculator.math.functions.Power;
import org.warp.picalculator.math.functions.RootSquare;
import org.warp.picalculator.math.functions.Subtraction;
import org.warp.picalculator.math.functions.Sum;
import org.warp.picalculator.math.functions.SumSubtraction;
@ -29,12 +35,17 @@ import org.warp.picalculator.math.parser.features.FeatureChar;
import org.warp.picalculator.math.parser.features.FeatureDivision;
import org.warp.picalculator.math.parser.features.FeatureMultiplication;
import org.warp.picalculator.math.parser.features.FeatureNumber;
import org.warp.picalculator.math.parser.features.FeatureParenthesis;
import org.warp.picalculator.math.parser.features.FeaturePower;
import org.warp.picalculator.math.parser.features.FeatureSquareRoot;
import org.warp.picalculator.math.parser.features.FeatureSum;
import org.warp.picalculator.math.parser.features.FeatureVariable;
import org.warp.picalculator.math.parser.features.interfaces.Feature;
import org.warp.picalculator.math.parser.features.interfaces.FeatureDouble;
import org.warp.picalculator.math.parser.features.interfaces.FeatureSingle;
import com.sun.org.apache.xpath.internal.functions.Function2Args;
import com.sun.org.apache.xpath.internal.operations.Mult;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
@ -50,7 +61,7 @@ public class MathParser {
return result;
}
public static ObjectArrayList<Block> parseOutput(MathContext context, ObjectArrayList<Function> expr) {
public static ObjectArrayList<Block> parseOutput(MathContext context, ObjectArrayList<Function> expr) throws Error {
final ObjectArrayList<Block> resultBlocks = new ObjectArrayList<>();
for (Function f : expr) {
@ -60,7 +71,7 @@ public class MathParser {
return resultBlocks;
}
private static ObjectArrayList<Block> parseFunction(MathContext context, Function func) {
private static ObjectArrayList<Block> parseFunction(MathContext context, Function func) throws Error {
ObjectArrayList<Block> result = new ObjectArrayList<>();
if (func instanceof FunctionOperator) {
ObjectArrayList<Block> sub1 = parseFunction(context, func.getParameter(0));
@ -71,23 +82,124 @@ public class MathParser {
result.addAll(sub2);
return result;
}
if (func instanceof Subtraction) {
result.addAll(sub1);
result.add(new BlockChar(MathematicalSymbols.SUBTRACTION));
result.addAll(sub2);
return result;
}
if (func instanceof SumSubtraction) {
result.addAll(sub1);
result.add(new BlockChar(MathematicalSymbols.SUM_SUBTRACTION));
result.addAll(sub2);
return result;
}
if (func instanceof Multiplication) {
Block nearLeft = sub1.get(sub1.size()-1);
Block nearRight = sub2.get(0);
result.addAll(sub1);
if (nearLeft instanceof BlockChar && nearRight instanceof BlockChar) {
} else {
result.add(new BlockChar(MathematicalSymbols.MULTIPLICATION));
}
result.addAll(sub2);
return result;
}
if (func instanceof Division) {
BlockDivision bd = new BlockDivision();
BlockContainer uc = bd.getUpperContainer();
BlockContainer lc = bd.getLowerContainer();
for (Block b : sub1) {
uc.appendBlockUnsafe(b);
}
for (Block b : sub2) {
lc.appendBlockUnsafe(b);
}
uc.recomputeDimensions();
lc.recomputeDimensions();
bd.recomputeDimensions();
result.add(bd);
return result;
}
if (func instanceof Power) {
BlockPower bp = new BlockPower();
BlockContainer nc = bp.getNumberContainer();
BlockContainer ec = bp.getExponentContainer();
for (Block b : sub1) {
nc.appendBlockUnsafe(b);
}
for (Block b : sub2) {
ec.appendBlockUnsafe(b);
}
nc.recomputeDimensions();
ec.recomputeDimensions();
bp.recomputeDimensions();
result.add(bp);
return result;
}
}
if (func instanceof FunctionSingle) {
ObjectArrayList<Block> sub = parseFunction(context, func.getParameter(0));
if (func instanceof RootSquare) {
BlockSquareRoot bsqr = new BlockSquareRoot();
BlockContainer bsqrc = bsqr.getNumberContainer();
for (Block b : sub) {
bsqrc.appendBlockUnsafe(b);
}
bsqrc.recomputeDimensions();
bsqr.recomputeDimensions();
result.add((bsqr));
return result;
}
}
if (func instanceof Expression) {
ObjectArrayList<Block> sub = parseFunction(context, ((Expression) func).getParameter(0));
BlockParenthesis bp = new BlockParenthesis();
BlockContainer bpc = bp.getNumberContainer();
for (Block b : sub) {
bpc.appendBlockUnsafe(b);
}
bpc.recomputeDimensions();
bp.recomputeDimensions();
result.add(bp);
return result;
}
if (func instanceof Number) {
Number numb = (Number) func;
BigDecimal decimal = numb.getTerm();
String numberString;
if (numb.isInteger()) {
BigInteger integ = decimal.toBigInteger();
numberString = integ.toString();
} else {
numberString = decimal.toPlainString();
String numberString = numb.toString();
if (numberString.contains("")) {
String[] numberParts = numberString.split("", 2);
numberParts[0]+="";
BlockPower bp = new BlockExponentialNotation();
BlockContainer bpnc = bp.getNumberContainer();
BlockContainer bpec = bp.getExponentContainer();
for (char c : numberParts[0].toCharArray()) {
bpnc.appendBlockUnsafe(new BlockChar(c));
}
for (char c : numberParts[1].toCharArray()) {
bpec.appendBlockUnsafe(new BlockChar(c));
}
bpnc.recomputeDimensions();
bpec.recomputeDimensions();
bp.recomputeDimensions();
result.add(bp);
return result;
} else {
for (char c : numberString.toCharArray()) {
result.add(new BlockChar(c));
}
}
return result;
}
throw new UnsupportedOperationException("Unknown function " + func.getClass().getSimpleName());
if (func instanceof Variable) {
//TODO: Temporary solution. In near future Variables will be distint objects and they will have a color. So they will be no longer a BlockChar/FeatureChar
result.add(new BlockChar(((Variable) func).getChar()));
return result;
}
throw new Error(Errors.NOT_IMPLEMENTED, "Unknown function " + func.getClass().getSimpleName());
}
private static Function parseContainer(final MathContext context, final Iterable<Block> blocks) throws Error {
@ -117,8 +229,24 @@ public class MathParser {
final Function lower = parseContainer(context, bd.getLowerContainer().getContent());
result = new FeatureDivision(upper, lower);
break;
case BlockSquareRoot.CLASS_ID:
final BlockSquareRoot bsqr = (BlockSquareRoot) block;
final Function contnt = parseContainer(context, bsqr.getNumberContainer().getContent());
result = new FeatureSquareRoot(contnt);
break;
case BlockParenthesis.CLASS_ID:
final BlockParenthesis bp = (BlockParenthesis) block;
final Function cont = parseContainer(context, bp.getNumberContainer().getContent());
result = new FeatureParenthesis(cont);
break;
case BlockPower.CLASS_ID:
final BlockPower blp = (BlockPower) block;
final Function nmb = parseContainer(context, blp.getNumberContainer().getContent());
final Function exp = parseContainer(context, blp.getExponentContainer().getContent());
result = new FeaturePower(nmb, exp);
break;
default:
throw new Error(Errors.SYNTAX_ERROR);
throw new Error(Errors.NOT_IMPLEMENTED, "The block " + block.getClass().getSimpleName() + " isn't a known BLock");
}
return result;
@ -141,14 +269,43 @@ public class MathParser {
private static void fixStack(MathContext context, ObjectArrayList<Function> process) throws Error {
boolean lastLoopDidSomething;
ObjectListIterator<Function> stackIterator;
//Phase 0: join number and variables ([2][x] => [[2]*[x]])
do {
lastLoopDidSomething = false;
stackIterator = process.listIterator(process.size());
Function lastElement = null;
while (stackIterator.hasPrevious()) {
final Function f = stackIterator.previous();
final int curIndex = stackIterator.nextIndex();
if (f instanceof Number | f instanceof Variable) {
if (lastElement instanceof Variable) {
lastLoopDidSomething = true;
final Function var = process.get(curIndex + 1);
final Function numb = process.get(curIndex);
stackIterator.set(new Multiplication(context, numb, var));
process.remove(curIndex + 1);
}
}
lastElement = f;
}
} while (lastLoopDidSomething);
//Phase 1
ObjectListIterator<Function> stackIterator = process.listIterator(process.size());
do {
lastLoopDidSomething = false;
stackIterator = process.listIterator(process.size());
Function lastElement = null;
while (stackIterator.hasPrevious()) {
final Function f = stackIterator.previous();
if (f instanceof FunctionSingle) {
if (((FunctionSingle) f).getParameter() == null) {
lastLoopDidSomething = true;
if (lastElement == null) {
throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified.");
} else {
@ -159,8 +316,11 @@ public class MathParser {
}
lastElement = f;
}
} while (lastLoopDidSomething);
//Phase 2
do {
lastLoopDidSomething = false;
stackIterator = process.listIterator();
while (stackIterator.hasNext()) {
final Function f = stackIterator.next();
@ -168,6 +328,7 @@ public class MathParser {
if (f instanceof Multiplication || f instanceof Division) {
if (curIndex - 1 >= 0 && stackIterator.hasNext()) {
lastLoopDidSomething = true;
final Function next = process.get(curIndex + 1);
final Function prev = process.get(curIndex - 1);
stackIterator.set(f.setParameter(0, prev).setParameter(1, next));
@ -180,8 +341,11 @@ public class MathParser {
}
}
}
} while (lastLoopDidSomething);
//Phase 3
do {
lastLoopDidSomething = false;
stackIterator = process.listIterator();
while (stackIterator.hasNext()) {
final Function f = stackIterator.next();
@ -189,6 +353,7 @@ public class MathParser {
if (f instanceof Sum || f instanceof Subtraction || f instanceof SumSubtraction) {
if (curIndex - 1 >= 0 && stackIterator.hasNext()) {
lastLoopDidSomething = true;
final Function next = process.get(curIndex + 1);
final Function prev = process.get(curIndex - 1);
stackIterator.set(f.setParameter(0, prev).setParameter(1, next));
@ -201,8 +366,11 @@ public class MathParser {
}
}
}
} while (lastLoopDidSomething);
//Phase 4
do {
lastLoopDidSomething = false;
stackIterator = process.iterator();
while (stackIterator.hasNext()) {
final Function f = stackIterator.next();
@ -211,6 +379,7 @@ public class MathParser {
}
}
} while (lastLoopDidSomething);
}
private static ObjectArrayList<Function> makeFunctions(MathContext context, ObjectArrayList<Feature> features)
@ -226,6 +395,12 @@ public class MathParser {
process.add(new Variable(context, ((FeatureVariable) f).ch, ((FeatureVariable) f).varType));
} else if (f instanceof FeatureSum) {
process.add(new Sum(context, (Function) ((FeatureDouble) f).getChild1(), (Function) ((FeatureDouble) f).getChild2()));
} else if (f instanceof FeaturePower) {
process.add(new Power(context, (Function) ((FeatureDouble) f).getChild1(), (Function) ((FeatureDouble) f).getChild2()));
} else if (f instanceof FeatureSquareRoot) {
process.add(new RootSquare(context, (Function) ((FeatureSingle) f).getChild()));
} else if (f instanceof FeatureParenthesis) {
process.add(new Expression(context, (Function) ((FeatureSingle) f).getChild()));
// } else if (f instanceof FeatureSubtraction) {
// process.add(new Subtraction(context, (Function) ((FeatureDouble) f).getChild1(), (Function) ((FeatureDouble) f).getChild2()));
// } else if (f instanceof FeatureSumSubtraction) {
@ -321,7 +496,7 @@ public class MathParser {
break;
}
}
if (bcf.ch == '-') {
if (bcf.ch == '-' || bcf.ch == '.') {
isNumber = true;
}
if (isNumber) {

View File

@ -0,0 +1,9 @@
package org.warp.picalculator.math.parser.features;
public class FeatureParenthesis extends FeatureSingleImpl {
public FeatureParenthesis(Object child) {
super(child);
}
}

View File

@ -0,0 +1,11 @@
package org.warp.picalculator.math.parser.features;
import org.warp.picalculator.math.parser.features.interfaces.Feature;
public class FeaturePower extends FeatureDoubleImpl {
public FeaturePower(Object child1, Object child2) {
super(child1, child2);
}
}

View File

@ -0,0 +1,9 @@
package org.warp.picalculator.math.parser.features;
public class FeatureSquareRoot extends FeatureSingleImpl {
public FeatureSquareRoot(Object child) {
super(child);
}
}