/*
* 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 java.awt.geom.NoninvertibleTransformException;
import org.antlr.v4.runtime.Token;
class ASTModTerm extends ASTExpression {
private int argCount;
private EModType modType;
private ASTExpression args;
public ASTModTerm(EModType modType, ASTExpression args, Token location) {
super(true, false, EExpType.ModType, location);
this.modType = modType;
this.args = args;
this.argCount = 0;
if (args.type == EExpType.RuleType)
throw new RuntimeException("Illegal expression in shape adjustment");
if (args.type == EExpType.ModType) {
if (modType != EModType.transform)
throw new RuntimeException(
"Cannot accept a transform expression here");
modType = EModType.modification;
}
}
public ASTModTerm(EModType param, String entropy, Token location) {
super(true, false, EExpType.ModType, location);
// TODO Auto-generated constructor stub
}
public ASTModTerm(EModType param, Token location) {
super(true, false, EExpType.ModType, location);
// TODO Auto-generated constructor stub
}
public EModType getModType() {
return modType;
}
public void setModType(EModType modType) {
this.modType = modType;
}
public ASTExpression getArguments() {
return args;
}
public void setArguments(ASTExpression arguments) {
this.args = arguments;
}
public int getArgumentsCount() {
return argCount;
}
public void setArgumentsCount(int argCount) {
this.argCount = argCount;
}
@Override
public void entropy(StringBuilder e) {
if (args != null) {
args.entropy(e);
}
e.append(modType.getEntropy());
}
@Override
public int evaluate(double[] result, int length, RTI rti) {
error("Improper evaluation of an adjustment expression");
return -1;
}
@Override
public void evaluate(Modification[] result, boolean shapeDest, RTI rti) {
double[] modArgs = new double[6];
int argcount = 0;
if (args != null) {
if (modType != EModType.modification && args.type == EExpType.NumericType) {
argcount = args.evaluate(modArgs, 6, rti);
} else if (modType == EModType.modification && args.type != EExpType.ModType) {
error("Adjustments require numeric arguments");
return;
}
}
if (argcount != argCount) {
error("Error evaluating arguments");
return;
}
double[] args = new double[6];
for (int i = 0; i < argcount; ++i) {
args[i] = Math.max(-1.0, Math.min(1.0, modArgs[i]));
}
double[] color = result[0].color().values();
double[] target = result[0].colorTarget().values();
int colorComp = 0;
boolean hue = true;
long mask = EAssignmentType.HueMask.ordinal();
switch (modType) {
case x: {
if (argcount == 1) {
modArgs[1] = 0.0;
}
AffineTransform t2d = AffineTransform.getTranslateInstance(modArgs[0], modArgs[1]);
result[0].getTransform().preConcatenate(t2d);
break;
}
case y: {
AffineTransform t2d = AffineTransform.getTranslateInstance(0.0, modArgs[0]);
result[0].getTransform().preConcatenate(t2d);
break;
}
case z: {
AffineTransform1D t1d = AffineTransform1D.getTranslateInstance(modArgs[0]);
result[0].getTransformZ().preConcatenate(t1d);
break;
}
case xyz: {
AffineTransform t2d = AffineTransform.getTranslateInstance(modArgs[0], modArgs[1]);
AffineTransform1D t1d = AffineTransform1D.getTranslateInstance(modArgs[0]);
result[0].getTransform().preConcatenate(t2d);
result[0].getTransformZ().preConcatenate(t1d);
break;
}
case time: {
AffineTransformTime tTime = AffineTransformTime.getTranslateInstance(modArgs[0], modArgs[1]);
result[0].getTransformTime().preConcatenate(tTime);
break;
}
case timescale: {
AffineTransformTime tTime = AffineTransformTime.getScaleInstance(modArgs[0]);
result[0].getTransformTime().preConcatenate(tTime);
break;
}
case transform: {
switch (argcount) {
case 2:
case 1:
{
if (argcount == 1) {
modArgs[1] = 0.0;
}
AffineTransform t2d = AffineTransform.getTranslateInstance(modArgs[0], modArgs[1]);
result[0].getTransform().preConcatenate(t2d);
}
break;
case 4:
{
AffineTransform t2d = new AffineTransform();
double dx = modArgs[2] - modArgs[0];
double dy = modArgs[3] - modArgs[1];
double s = Math.hypot(dx, dy);
t2d.rotate(Math.atan2(dx, dy));
t2d.scale(s, s);
t2d.translate(modArgs[0], modArgs[1]);
result[0].getTransform().preConcatenate(t2d);
}
break;
case 6:
{
try {
AffineTransform t2d = new AffineTransform(modArgs[2] - modArgs[0], modArgs[3] - modArgs[1], modArgs[4] - modArgs[0], modArgs[5] - modArgs[1], modArgs[0], modArgs[1]);
AffineTransform par = new AffineTransform();
par.shear(1, 0);
par.invert();
par.concatenate(t2d);
result[0].getTransform().preConcatenate(par);
} catch (NoninvertibleTransformException e) {
error(e.getMessage());
}
}
break;
default:
break;
}
break;
}
case size: {
if (argcount == 1) {
modArgs[1] = modArgs[0];
}
AffineTransform t2d = AffineTransform.getScaleInstance(modArgs[0], modArgs[1]);
result[0].getTransform().preConcatenate(t2d);
break;
}
case sizexyz: {
AffineTransform t2d = AffineTransform.getScaleInstance(modArgs[0], modArgs[1]);
AffineTransform1D t1d = AffineTransform1D.getScaleInstance(modArgs[0]);
result[0].getTransform().preConcatenate(t2d);
result[0].getTransformZ().preConcatenate(t1d);
break;
}
case zsize: {
AffineTransform1D t1d = AffineTransform1D.getScaleInstance(modArgs[0]);
result[0].getTransformZ().preConcatenate(t1d);
break;
}
case rot: {
AffineTransform t2d = AffineTransform.getRotateInstance(modArgs[0] * Math.PI / 180.0);
result[0].getTransform().preConcatenate(t2d);
break;
}
case skew: {
AffineTransform t2d = AffineTransform.getShearInstance(modArgs[0] * Math.PI / 180.0, modArgs[1] * Math.PI / 180.0);
result[0].getTransform().preConcatenate(t2d);
break;
}
case flip: {
double a = modArgs[0] * Math.PI / 180.0;
double ux = Math.cos(a);
double uy = Math.cos(a);
AffineTransform t2d = new AffineTransform(2.0 * ux * ux - 1.0, 2.0 * ux * uy, 2.0 * ux * uy, 2.0 * uy * uy - 1.0, 0.0, 0.0);
result[0].getTransform().preConcatenate(t2d);
break;
}
case alpha:
case bright:
case sat:
{
colorComp += modType.ordinal() - EModType.hue.ordinal();
mask <<= 2 * modType.ordinal() - EModType.hue.ordinal();
hue = false;
}
case hue:
{
if (argcount == 1) {
if ((result[0].colorAssignment() & mask) != 0 || (!hue && color[colorComp] != 0.0)) {
if (rti == null) throw new DeferUntilRuntimeException();
if (!shapeDest) {
rti.colorConflict();
}
}
if (shapeDest) {
color[colorComp] = hue ? HSBColor.adjustHue(color[colorComp], modArgs[0]) : HSBColor.adjust(color[colorComp], modArgs[0]);
} else {
color[colorComp] = hue ? color[colorComp] + modArgs[0] : args[0];
}
} else {
if ((result[0].colorAssignment() & mask) != 0 || (color[colorComp] != 0.0) || (!hue && target[colorComp] != 0.0)) {
if (rti == null) throw new DeferUntilRuntimeException();
if (!shapeDest) {
rti.colorConflict();
}
}
if (shapeDest) {
color[colorComp] = hue ? HSBColor.adjustHue(color[colorComp], args[0], EAssignmentType.HueTarget, modArgs[1]) : HSBColor.adjust(color[colorComp], args[0], EAssignmentType.ColorTarget, args[1]);
} else {
color[colorComp] = args[0];
target[colorComp] = hue ? modArgs[1] : args[1];
result[0].setColorAssignment(result[0].colorAssignment() | EAssignmentType.HSBA2Value.ordinal() & mask);
}
}
}
break;
case alphaTarg:
case brightTarg:
case satTarg:
{
colorComp += modType.ordinal() - EModType.hueTarg.ordinal();
mask <<= 2 * modType.ordinal() - EModType.hueTarg.ordinal();
hue = false;
}
case hueTarg:
{
if ((result[0].colorAssignment() & mask) != 0 || (color[colorComp] != 0.0)) {
if (rti == null) throw new DeferUntilRuntimeException();
if (!shapeDest) {
rti.colorConflict();
}
}
if (shapeDest) {
color[colorComp] = hue ? HSBColor.adjustHue(color[colorComp], args[0], EAssignmentType.HueTarget, target[colorComp]) : HSBColor.adjust(color[colorComp], args[0], EAssignmentType.ColorTarget, target[colorComp]);
} else {
color[colorComp] = args[0];
result[0].setColorAssignment(result[0].colorAssignment() | EAssignmentType.HSBATarget.ordinal() & mask);
}
}
break;
case targAlpha:
case targBright:
case targSat:
{
colorComp += modType.ordinal() - EModType.targHue.ordinal();
mask <<= 2 * modType.ordinal() - EModType.targHue.ordinal();
if (target[colorComp] != 0.0) {
if (rti == null) throw new DeferUntilRuntimeException();
if (!shapeDest) {
rti.colorConflict();
}
}
if (shapeDest) {
target[colorComp] = HSBColor.adjust(target[colorComp], args[0]);
} else {
target[colorComp] = args[0];
}
}
break;
case targHue:
{
target[0] += modArgs[0];
}
break;
case param: {
error("Cannot provide a parameter in this context");
break;
}
case stroke: {
error("Cannot provide a stroke width in this context");
break;
}
case modification: {
if (rti == null) {
if (args != null && getArguments() instanceof ASTModification) {
ASTModification mod = (ASTModification)getArguments();
if ((mod.getModClass().ordinal() & (EModClass.HueClass.ordinal() | EModClass.HueTargetClass.ordinal() | EModClass.BrightClass.ordinal() | EModClass.BrightTargetClass.ordinal() | EModClass.SatClass.ordinal() | EModClass.SatTargetClass.ordinal() | EModClass.AlphaClass.ordinal() | EModClass.AlphaTargetClass.ordinal())) != 0) {
throw new DeferUntilRuntimeException();
}
}
}
getArguments().evaluate(result, shapeDest, rti);
break;
}
default:
break;
}
}
@Override
public ASTExpression simplify() {
if (args != null) {
args = args.simplify();
}
return this;
}
@Override
public ASTExpression compile(ECompilePhase ph) {
if (args != null) {
args = args.compile(ph);
}
if (args == null) {
if (modType == EModType.param) {
error("Illegal expression in shape adjustment");
return null;
}
}
switch (ph) {
case TypeCheck:
{
isConstant = args.isConstant();
locality = args.getLocality();
switch (args.getType()) {
case NumericType:
{
argCount = args.evaluate(null, 0);
int minCount = 1;
int maxCount = 1;
if (argCount == 3 && modType == EModType.x) {
modType = EModType.xyz;
}
if (argCount == 3 && modType == EModType.size) {
modType = EModType.sizexyz;
}
switch (modType) {
case x:
case size:
case hue:
case sat:
case bright:
case alpha:
maxCount = 2;
break;
case y:
case z:
case timescale:
case zsize:
case rot:
case flip:
case hueTarg:
case satTarg:
case brightTarg:
case alphaTarg:
case targHue:
case targSat:
case targBright:
case targAlpha:
case stroke:
break;
case xyz:
case sizexyz:
minCount = maxCount = 3;
break;
case time:
case skew:
minCount = maxCount = 2;
break;
case transform:
maxCount = 6;
if (argCount != 1 && argCount != 2 && argCount != 4 && argCount != 6) {
error("transform adjustment takes 1, 2, 4, or 6 parameters");
}
break;
case param:
minCount = maxCount = 0;
break;
case modification:
break;
default:
break;
}
if (argCount < minCount) {
error("Not enough adjustment parameters");
}
if (argCount > maxCount) {
error("Too many adjustment parameters");
}
}
break;
case ModType:
{
if (modType != EModType.transform) {
error("Cannot accept a transform expression here");
} else {
modType = EModType.modification;
}
}
break;
default:
error("Illegal expression in shape adjustment");
break;
}
}
break;
case Simplify:
break;
default:
break;
}
return null;
}
}