/* * 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.PathIterator; import org.antlr.v4.runtime.Token; class ASTRule extends ASTReplacement implements Comparable<ASTRule> { private ASTRepContainer ruleBody = new ASTRepContainer(); private ASTCompiledPath cachedPath; private float weight; private boolean isPath; private int nameIndex; private EWeightType weightType; public ASTRule(int nameIndex, float weight, boolean percent, Token location) { super(null, ERepElemType.rule, location); this.nameIndex = nameIndex; this.isPath = false; this.weight = weight <= 0.0 ? 1.0f : weight; this.weightType = percent ? EWeightType.PercentWeight : EWeightType.ExplicitWeight; this.cachedPath = null; } public ASTRule(int nameIndex, Token location) { super(null, ERepElemType.rule, location); this.nameIndex = nameIndex; this.isPath = false; this.weight = 1.0f; this.weightType = EWeightType.NoWeight; this.cachedPath = null; } protected ASTRule(int nameIndex, Token location, boolean dummy) { super(null, ERepElemType.rule, location); this.nameIndex = nameIndex; this.isPath = true; this.weight = 1.0f; this.weightType = EWeightType.NoWeight; this.cachedPath = null; if (nameIndex != EPrimShape.circleType.getType()) { PrimShape shape = PrimShape.getShapeMap().get(nameIndex); double[] coords = new double[6]; int cmd; PathIterator iterator = shape.getPathIterator(); while (!isStop(cmd = iterator.currentSegment(coords))) { if (isVertex(cmd)) { ASTExpression a = new ASTCons(location, new ASTReal(coords[0], location), new ASTReal(coords[1], location)); ASTPathOp op = new ASTPathOp(isMoveTo(cmd) ? EPathOp.MOVETO.name() : EPathOp.LINETO.name(), a, location); getRuleBody().getBody().add(op); } } } else { ASTExpression a = new ASTCons(location, new ASTReal(0.5, location), new ASTReal(0.0, location)); ASTPathOp op = new ASTPathOp(EPathOp.MOVETO.name(), a, location); getRuleBody().getBody().add(op); a = new ASTCons(location, new ASTReal(-0.5, location), new ASTReal(0.0, location), new ASTReal(0.5, location)); op = new ASTPathOp(EPathOp.ARCTO.name(), a, location); getRuleBody().getBody().add(op); a = new ASTCons(location, new ASTReal(0.5, location), new ASTReal(0.0, location), new ASTReal(0.5, location)); op = new ASTPathOp(EPathOp.ARCTO.name(), a, location); getRuleBody().getBody().add(op); } getRuleBody().getBody().add(new ASTPathOp(EPathOp.CLOSEPOLY.name(), null, location)); getRuleBody().setRepType(ERepElemType.op.getType()); getRuleBody().setPathOp(EPathOp.MOVETO); } private boolean isMoveTo(int cmd) { return cmd == PathIterator.SEG_MOVETO; } private boolean isVertex(int cmd) { return cmd >= PathIterator.SEG_MOVETO && cmd < PathIterator.SEG_CLOSE; } private boolean isStop(int cmd) { return cmd == PathIterator.SEG_CLOSE; } public ASTRepContainer getRuleBody() { return ruleBody; } public float getWeight() { return weight; } public EWeightType getWeightType() { return weightType; } public boolean isPath() { return isPath; } public void setPath(boolean isPath) { this.isPath = isPath; } public int getNameIndex() { return nameIndex; } public void setNameIndex(int nameIndex) { this.nameIndex = nameIndex; } @Override public void compile(ECompilePhase ph) { Builder.currentBuilder().setInPathContainer(isPath); super.compile(ph); ruleBody.compile(ph, null, null); } @Override public void traverse(Shape parent, boolean tr, RTI rti) { rti.setCurrentSeed(parent.getWorldState().getRand64Seed()); if (isPath) { rti.processPrimShape(parent, this); } else { ruleBody.traverse(parent, tr, rti, true); parent.releaseParams(); } } public void traversePath(Shape parent, RTI rti) { rti.init(); rti.setCurrentSeed(parent.getWorldState().getRand64Seed()); rti.setRandUsed(false); ASTCompiledPath savedPath = null; if (cachedPath != null && cachedPath.getParameters().equals(parent.getParameters())) { savedPath = rti.getCurrentPath(); rti.setCurrentPath(cachedPath); rti.setCurrentCommand(cachedPath.getCommandInfo().iterator()); } ruleBody.traverse(parent, false, rti, true); if (!rti.getCurrentPath().isComplete()) { rti.getCurrentPath().finish(true, rti); } if (rti.getCurrentPath().useTerminal()) { rti.getCurrentPath().getTerminalCommand().traverse(parent, false, rti); } if (savedPath != null) { rti.setCurrentPath(savedPath); } else { if (rti.isRandUsed() && cachedPath == null) { cachedPath = rti.getCurrentPath(); cachedPath.setIsComplete(true); cachedPath.setParameters(new StackRule(parent.getParameters())); rti.setCurrentPath(new ASTCompiledPath(getLocation())); } else { rti.getCurrentPath().getPath().clear(); rti.getCurrentPath().getCommandInfo().clear(); rti.getCurrentPath().setUseTerminal(false); rti.getCurrentPath().setPathUID(ASTCompiledPath.nextPathUID()); if (rti.getCurrentPath().getParameters() != null) { rti.getCurrentPath().setParameters(null); } } } } @Override public int compareTo(ASTRule o) { return nameIndex == o.nameIndex ? (weight < o.weight ? -1 : weight == o.weight ? 0 : 1) : nameIndex - o.nameIndex; } }