/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.contextfree.parser; import java.awt.geom.AffineTransform; import org.antlr.v4.runtime.Token; class ASTPathOp extends ASTReplacement { private ASTExpression arguments; private ASTModification oldStyleArguments; private int argCount; private int flags; public ASTPathOp(String op, ASTModification args, Token location) { super(op, location); this.arguments = null; this.oldStyleArguments = args; this.argCount = 0; this.flags = 0; } public ASTPathOp(String op, ASTExpression args, Token location) { super(op, location); this.arguments = args; this.oldStyleArguments = null; this.argCount = 0; this.flags = 0; } public ASTExpression getArguments() { return arguments != null ? arguments : oldStyleArguments; } public int getArgCount() { return argCount; } public int getFlags() { return flags; } @Override public void compile(ECompilePhase ph) { super.compile(ph); if (arguments != null) { arguments.compile(ph); } if (oldStyleArguments != null) { oldStyleArguments.compile(ph); } switch (ph) { case TypeCheck: if (oldStyleArguments != null) { makePositional(); } else { checkArguments(); } break; case Simplify: pathDataConst(); if (arguments != null) { arguments.simplify(); } break; default: break; } } private void pathDataConst() { if (arguments != null && arguments.isConstant()) { double[] data = new double[7]; if (arguments.evaluate(data, 7) < 0) { error("Cannot evaluate arguments"); } arguments = null; getChildChange().getModData().setTransform(new AffineTransform(data)); } } private void checkArguments() { if (arguments != null) { argCount = arguments.evaluate(null, 0); } for (int i = 0; arguments != null && i < arguments.size(); i++) { ASTExpression temp = arguments.getChild(i); switch (temp.getType()) { case FlagType: if (i != arguments.size() - 1) { error("Flags must be the last argument"); } if (temp instanceof ASTReal) { ASTReal rf = (ASTReal)temp; flags |= (int)rf.getValue(); } else { error("Flag expressions must be constant"); } argCount--; break; case NumericType: break; default: error("Path operation arguments must be numeric expressions or flags"); break; } } switch (getPathOp()) { case LINETO: case LINEREL: case MOVETO: case MOVEREL: if (argCount != 2) { error("Move/line path operation requires two arguments"); } break; case ARCTO: case ARCREL: if (argCount != 3 && argCount != 5) { error("Arc path operations require three or five arguments"); } break; case CURVETO: case CURVEREL: if ((flags & EFlagType.CF_CONTINUOUS.getType()) != 0) { if (argCount != 2 && argCount != 4) { error("Continuous curve path operations require two or four arguments"); } } else { if (argCount != 4 && argCount != 6) { error("Non-continuous curve path operations require four or six arguments"); } } break; case CLOSEPOLY: if (argCount > 0) { error("CLOSEPOLY takes no arguments, only flags"); } break; default: break; } } private void makePositional() { // TODO da completare // exp_ptr w = GetFlagsAndStroke(mOldStyleArguments->modExp, mFlags); // if (w) // CfdgError::Error(w->where, "Stroke width not allowed in a path operation"); // // exp_ptr ax; // exp_ptr ay; // exp_ptr ax1; // exp_ptr ay1; // exp_ptr ax2; // exp_ptr ay2; // exp_ptr arx; // exp_ptr ary; // exp_ptr ar; // // for (term_ptr& mod: mOldStyleArguments->modExp) { // if (!mod) // continue; // switch (mod->modType) { // case ASTmodTerm::x: // acquireTerm(ax, mod); // break; // case ASTmodTerm::y: // acquireTerm(ay, mod); // break; // case ASTmodTerm::x1: // acquireTerm(ax1, mod); // break; // case ASTmodTerm::y1: // acquireTerm(ay1, mod); // break; // case ASTmodTerm::x2: // acquireTerm(ax2, mod); // break; // case ASTmodTerm::y2: // acquireTerm(ay2, mod); // break; // case ASTmodTerm::xrad: // acquireTerm(arx, mod); // break; // case ASTmodTerm::yrad: // acquireTerm(ary, mod); // break; // case ASTmodTerm::rot: // acquireTerm(ar, mod); // break; // case ASTmodTerm::z: // case ASTmodTerm::zsize: // CfdgError::Error(mod->where, "Z changes are not permitted in paths"); // break; // case ASTmodTerm::unknownType: // default: // CfdgError::Error(mod->where, "Unrecognized element in a path operation"); // break; // } // } // // ASTexpression* xy = nullptr; // if (mPathOp != CLOSEPOLY) { // xy = parseXY(std::move(ax), std::move(ay), 0.0, mLocation); // } // // switch (mPathOp) { // case LINETO: // case LINEREL: // case MOVETO: // case MOVEREL: // mArguments.reset(xy); // break; // case ARCTO: // case ARCREL: // if (arx || ary) { // ASTexpression* rxy = parseXY(std::move(arx), std::move(ary), 1.0, mLocation); // ASTexpression* angle = ar.release(); // if (!angle) // angle = new ASTreal(0.0, mLocation); // // if (angle->mType != NumericType || angle->evaluate(nullptr, 0) != 1) // CfdgError(angle->where, "Arc angle must be a scalar value"); // // mArguments.reset(xy->append(rxy)->append(angle)); // } else { // ASTexpression* radius = ar.release(); // if (!radius) // radius = new ASTreal(1.0, mLocation); // // if (radius->mType != NumericType || radius->evaluate(nullptr, 0) != 1) // CfdgError::Error(radius->where, "Arc radius must be a scalar value"); // // mArguments.reset(xy->append(radius)); // } // break; // case CURVETO: // case CURVEREL: { // ASTexpression *xy1 = nullptr, *xy2 = nullptr; // if (ax1 || ay1) { // xy1 = parseXY(std::move(ax1), std::move(ay1), 0.0, mLocation); // } else { // mFlags |= CF_CONTINUOUS; // } // if (ax2 || ay2) { // xy2 = parseXY(std::move(ax2), std::move(ay2), 0.0, mLocation); // } // // mArguments.reset(xy->append(xy1)->append(xy2)); // break; // } // case CLOSEPOLY: // break; // default: // break; // } // // rejectTerm(ax); // rejectTerm(ay); // rejectTerm(ar); // rejectTerm(arx); // rejectTerm(ary); // rejectTerm(ax1); // rejectTerm(ay1); // rejectTerm(ax2); // rejectTerm(ay2); // // mArgCount = mArguments ? mArguments->evaluate(nullptr, 0) : 0; // mOldStyleArguments.reset(); } @Override public void traverse(Shape parent, boolean tr, RTI rti) { if (rti.getCurrentPath().isComplete()) { return; } double[] opData = new double[7]; pushData(opData, rti); rti.getCurrentPath().addPathOp(this, opData, parent, tr, rti); } private void pushData(double[] opData, RTI rti) { if (arguments != null) { if (arguments.evaluate(opData, 7, rti) < 0) { error("Cannot evaluate arguments"); } } else { getChildChange().getModData().getTransform().getMatrix(opData); } } }