/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.gui.swing.filter;
import java.awt.image.BufferedImage;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import net.sourceforge.jeuclid.LayoutContext.Parameter;
import net.sourceforge.jeuclid.MutableLayoutContext;
import net.sourceforge.jeuclid.context.LayoutContextImpl;
import net.sourceforge.jeuclid.converter.Converter;
import org.apache.sis.xml.MarshallerPool;
import org.geotoolkit.mathml.xml.MathMLUtilities;
import org.geotoolkit.mathml.xml.Mfenced;
import org.geotoolkit.mathml.xml.Mfrac;
import org.geotoolkit.mathml.xml.Mi;
import org.geotoolkit.mathml.xml.Mn;
import org.geotoolkit.mathml.xml.Mo;
import org.geotoolkit.mathml.xml.Mrow;
import org.geotoolkit.mathml.xml.ObjectFactory;
import org.opengis.filter.expression.Add;
import org.opengis.filter.expression.Divide;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.Multiply;
import org.opengis.filter.expression.NilExpression;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.expression.Subtract;
import org.w3c.dom.Document;
/**
* Convert and expression in MathML
* @author Johann Sorel (Geomatys)
*/
public final class MathMLVisitor implements ExpressionVisitor {
public static final MathMLVisitor INSTANCE = new MathMLVisitor();
private static final ObjectFactory MLFactory = new ObjectFactory();
private static final String MAGENTA = "#FF00FF";
private static final String GREEN = "#009600";
private static final String BLUE = "#0000FF";
private MathMLVisitor(){}
@Override
public Object visit(NilExpression expression, Object extraData) {
final String strVal = "NIL";
final Mi lit = new Mi();
lit.getContent().add(strVal);
return MLFactory.createMi(lit);
}
@Override
public Object visit(Add expression, Object extraData) {
final Expression exp1 = expression.getExpression1();
final Expression exp2 = expression.getExpression2();
final Mrow row = new Mrow();
final Mo operator = new Mo();
operator.getContent().add(" + ");
row.getMathExpression().add(fence(exp1.accept(this, extraData),exp1));
row.getMathExpression().add(MLFactory.createMo(operator));
row.getMathExpression().add(fence(exp2.accept(this, extraData),exp2));
return MLFactory.createMrow(row);
}
@Override
public Object visit(Divide expression, Object extraData) {
final Mfrac row = new Mfrac();
row.getContent().add(expression.getExpression1().accept(this, extraData));
row.getContent().add(expression.getExpression2().accept(this, extraData));
return MLFactory.createMfrac(row);
}
@Override
public Object visit(Function expression, Object extraData) {
final Mrow row = new Mrow();
final Mi lit = new Mi();
//lit.setMathvariant("bold");
lit.setMathcolor(MAGENTA);
lit.getContent().add(expression.getName());
row.getMathExpression().add(MLFactory.createMi(lit));
final Mfenced fence = new Mfenced();
for(Expression sub : expression.getParameters()){
fence.getMathExpression().add(sub.accept(this, extraData));
}
row.getMathExpression().add(MLFactory.createMfenced(fence));
return MLFactory.createMrow(row);
}
@Override
public Object visit(Literal expression, Object extraData) {
final Object obj = expression.getValue();
if(obj instanceof Number){
final Mn lit = new Mn();
lit.setMathcolor(GREEN);
lit.getContent().add(obj.toString());
return MLFactory.createMn(lit);
}else{
final String strVal = String.valueOf(obj);
final Mi lit = new Mi();
lit.setMathcolor(GREEN);
lit.getContent().add(strVal);
return MLFactory.createMi(lit);
}
}
@Override
public Object visit(Multiply expression, Object extraData) {
final Expression exp1 = expression.getExpression1();
final Expression exp2 = expression.getExpression2();
final Mrow row = new Mrow();
final Mo operator = new Mo();
operator.getContent().add(" × ");
row.getMathExpression().add(fence(exp1.accept(this, extraData),exp1));
row.getMathExpression().add(MLFactory.createMo(operator));
row.getMathExpression().add(fence(exp2.accept(this, extraData),exp2));
return MLFactory.createMrow(row);
}
@Override
public Object visit(PropertyName expression, Object extraData) {
final String strVal = String.valueOf(expression.getPropertyName());
final Mi prop = new Mi();
prop.setMathvariant("bold");
prop.setMathcolor(BLUE);
prop.getContent().add(strVal);
return MLFactory.createMi(prop);
}
@Override
public Object visit(Subtract expression, Object extraData) {
final Expression exp1 = expression.getExpression1();
final Expression exp2 = expression.getExpression2();
final Mrow row = new Mrow();
final Mo operator = new Mo();
operator.getContent().add(" − ");
row.getMathExpression().add(fence(exp1.accept(this, extraData),exp1));
row.getMathExpression().add(MLFactory.createMo(operator));
row.getMathExpression().add(fence(exp2.accept(this, extraData),exp2));
return MLFactory.createMrow(row);
}
private Object fence(Object element, Expression exp){
if(exp instanceof Literal || exp instanceof PropertyName || exp instanceof Function){
return element;
}else{
final Mfenced fence = new Mfenced();
fence.getMathExpression().add(element);
return MLFactory.createMfenced(fence);
}
}
public static Document toMathML(Expression exp) throws Exception{
final Object ele = exp.accept(INSTANCE, null);
final org.geotoolkit.mathml.xml.Math doc = new org.geotoolkit.mathml.xml.Math();
doc.getMathExpression().add(ele);
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final Document dom = builder.newDocument();
final MarshallerPool pool = MathMLUtilities.getMarshallerPool();
final Marshaller marshaller = pool.acquireMarshaller();
marshaller.marshal(doc, dom);
pool.recycle(marshaller);
return dom;
}
public static BufferedImage toImage(Document doc) throws Exception {
final MutableLayoutContext params = new LayoutContextImpl(LayoutContextImpl.getDefaultLayoutContext());
params.setParameter(Parameter.MATHSIZE, 25f);
return Converter.getConverter().render(doc, params);
}
}