/*
* Copyright (c) 2009, 2010, 2011 Daniel Rendall
* This file is part of FractDim.
*
* FractDim 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.
*
* FractDim 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 FractDim. If not, see <http://www.gnu.org/licenses/>
*/
package uk.co.danielrendall.fractdim.calculation;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import uk.co.danielrendall.fractdim.app.model.FractalDocument;
import uk.co.danielrendall.fractdim.logging.Log;
import uk.co.danielrendall.fractdim.svgbridge.FDTranscoder;
import uk.co.danielrendall.mathlib.geom2d.ParametricCurve;
import uk.co.danielrendall.mathlib.geom2d.Point;
import uk.co.danielrendall.mathlib.geom2d.Vec;
import uk.co.danielrendall.fractdim.calculation.grids.*;
import java.util.Set;
import java.util.HashSet;
/**
* @author Daniel Rendall
* @created 24-May-2009 11:00:39
*/
public class SquareCounter extends AbstractNotifyingGraphics {
private final GridCollection gridCollection;
private final Set<Grid> grids = new HashSet<Grid>();
private final int maxDepth;
public SquareCounter(FractalDocument fractalDocument, GridCollection gridCollection, int maxDepth) {
super(fractalDocument);
this.gridCollection = gridCollection;
this.maxDepth = maxDepth;
gridCollection.accept(new CollectionVisitorSupport() {
public void visit(DisplacementGridCollection collection) {
for (Vec v : collection.getAvailableDisplacements()) {
grids.add(collection.gridForDisplacement(v));
}
}
});
}
public void accept(CollectionVisitor visitor) {
gridCollection.accept(visitor);
}
public void doHandleCurve(ParametricCurve curve) {
evaluateBetween(curve, 0, 0.0d, 1.0d);
}
private void evaluateBetween(ParametricCurve curve, int depth, double rangeStart, double rangeEnd) {
Point start = curve.evaluate(rangeStart);
Point end = curve.evaluate(rangeEnd);
for (Grid grid : grids) {
grid.startEvaluation(start, end);
}
Set<Grid> temporarySet = new HashSet<Grid>();
temporarySet.addAll(grids);
evaluateBetween(curve, temporarySet, depth, rangeStart, start, rangeEnd, end);
for (Grid grid : grids) {
grid.endEvaluation();
}
}
// Note - when this is called, the start and end Squares have both been put in the store
private void evaluateBetween(ParametricCurve curve, Set<Grid> gridsToNotify, int depth,
double rangeStart, Point startPoint,
double rangeEnd, Point endPoint) {
if (depth > maxDepth) {
Log.app.warn("Max iteration depth reached - bailing out");
return;
}
final double rangeMid = (rangeStart + rangeEnd) / 2.0d;
if (Log.points.isDebugEnabled()) {
Log.points.debug(String.format("Parameter: Start: %09.9f Mid: %09.9f End: %09.9f", rangeStart, rangeMid, rangeEnd));
}
if ((rangeMid == rangeStart) || (rangeMid == rangeEnd)) {
// this should never happen
Log.app.warn(String.format("Underflow at depth: %d RangeStart: %s RangeEnd: %s", depth, rangeStart, rangeEnd));
return;
}
Point midPoint = curve.evaluate(rangeMid);
if (Log.points.isDebugEnabled()) {
Log.points.debug(String.format("Point Start: (%09.9f, %09.9f) Mid: (%09.9f, %09.9f) End: (%09.9f, %09.9f)",
startPoint.x(), startPoint.y(), midPoint.x(), midPoint.y(), endPoint.x(), endPoint.y()));
}
// notify all of the grids of the midsquare and see whether they're interested in recursing further
Set<Grid> gridsToRecurseStartMid = new HashSet<Grid>();
Set<Grid> gridsToRecurseMidEnd = new HashSet<Grid>();
for(Grid grid: gridsToNotify) {
boolean[] toRecurse = grid.notifyNewPoint(startPoint, midPoint, endPoint);
if (toRecurse[0] || depth <=2) gridsToRecurseStartMid.add(grid);
if (toRecurse[1] || depth <=2) gridsToRecurseMidEnd.add(grid);
}
if (Log.recursion.isDebugEnabled()) {
Log.recursion.debug(String.format("At depth %d, there were %d grids, %d want startToMid and %d want midToEnd", depth,
gridsToNotify.size(), gridsToRecurseStartMid.size(), gridsToRecurseMidEnd.size()));
}
if (gridsToRecurseStartMid.size() > 0) {
evaluateBetween(curve, gridsToRecurseStartMid, depth + 1, rangeStart, startPoint, rangeMid, midPoint);
}
if (gridsToRecurseMidEnd.size() > 0) {
evaluateBetween(curve, gridsToRecurseMidEnd, depth + 1, rangeMid, midPoint, rangeEnd, endPoint);
}
}
public int count() {
return grids.size();
}
public SquareCountingResult process() {
TranscoderInput input = new TranscoderInput(fractalDocument.getSvgDoc());
FDTranscoder transcoder = new FDTranscoder(this);
try {
transcoder.transcode(input, new TranscoderOutput());
} catch (TranscoderException e) {
Log.app.warn("Couldn't transcode at - " + e.getMessage());
}
Log.misc.info("There were " + GridSquare.createCount + " squares created");
return new SquareCountingResult(this.gridCollection.getCollection());
}
}