org.akraievoy.cnet.gen.domain.LocationGeneratorFractalDLA.java Source code

Java tutorial

Introduction

Here is the source code for org.akraievoy.cnet.gen.domain.LocationGeneratorFractalDLA.java

Source

/*
 Copyright 2011 Anton Kraievoy akraievoy@gmail.com
 This file is part of Holonet.
    
 Holonet 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.
    
 Holonet is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty
 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 Holonet. If not, see <http://www.gnu.org/licenses/>.
 */

package org.akraievoy.cnet.gen.domain;

import com.google.common.base.Optional;
import org.akraievoy.cnet.gen.vo.*;

public class LocationGeneratorFractalDLA extends LocationGeneratorBase {
    protected final EntropySource eSource;
    protected final WeightedEventModel eventModel;

    protected double dimensionRatio = 1.5;
    protected double densityRatio = 0.2;
    protected double genPointsRatio = 1.2;
    protected int generationNum = 12;
    protected int tryNum = 25;

    protected int seedPointNum = 1;

    protected double[] weights;

    public LocationGeneratorFractalDLA(final EntropySource eSource) {
        this.eSource = eSource;
        this.eventModel = new WeightedEventModelBase(Optional.of("locations"));
    }

    public void setDimensionRatio(double dimensionRatio) {
        this.dimensionRatio = dimensionRatio;
    }

    public void setGenerationNum(int generationNum) {
        this.generationNum = generationNum;
    }

    public void setDensityRatio(double densityRatio) {
        this.densityRatio = densityRatio;
    }

    public double getDimensionRatio() {
        return dimensionRatio;
    }

    public int getGenerationNum() {
        return generationNum;
    }

    public double getDensityRatio() {
        return densityRatio;
    }

    public int getTryNum() {
        return tryNum;
    }

    public void setTryNum(int tryNum) {
        this.tryNum = tryNum;
    }

    public void setGenPointsRatio(double genPointsRatio) {
        this.genPointsRatio = genPointsRatio;
    }

    public double getGenPointsRatio() {
        return genPointsRatio;
    }

    public int getSeedPointNum() {
        return seedPointNum;
    }

    public void run() {
        eSource.diagnoseSeed(this.getClass().getSimpleName());
        computeWeights();
    }

    protected void computeWeights() {
        weights = new double[cells];
        final int[] dirs = new int[] { -gridSize - 1, -gridSize, -gridSize + 1, 1, gridSize + 1, gridSize,
                gridSize - 1, -1 };

        final double totalWeight = Math.pow(gridSize, dimensionRatio);
        final double totalArea = totalWeight / densityRatio;

        double sum = 0;
        for (int g = 0; g < generationNum; g++) {
            sum += Math.pow(genPointsRatio, g);
        }

        final double genWeight = totalWeight / generationNum;
        double points = totalArea / sum;
        seedPointNum = (int) Math.floor(points);

        for (int g = 0; g < generationNum; g++) {
            if (g > 0) {
                points *= genPointsRatio;
            }
            final double pointWeight = genWeight / points;

            int tries = tryNum;
            for (int p = 0; p < points; tries--) {
                final int pos = eSource.nextInt(cells);

                if (g == 0 || tries == 0) { //   that's a seed (or tries exhausted), distribute it uniformly
                    weights[pos] += pointWeight;
                    p++;
                    tries = tryNum;
                    continue;
                }

                int dir = eSource.nextInt(dirs.length) % 8;

                int curPos = pos;
                while (isDep(curPos)) { //   atempting to drift out of deposit
                    curPos += dirs[dir];
                }
                if (!isPos(curPos)) { //   clipped off
                    continue;
                }

                int stepCounter = 0;
                while (isPos(curPos)) { //   drift to deposit, looking at near cells also
                    final int nextPos = curPos + dirs[dir];
                    final int nextPosL = curPos + dirs[(dir + 1) % 8];
                    final int nextPosR = curPos + dirs[(dir + 7) % 8];

                    if (isDep(nextPos) || isDep(nextPosL) || isDep(nextPosR)) {
                        break;
                    }

                    curPos = nextPos;
                    if (stepCounter % 8 == 0) {
                        dir = (dir + eSource.nextInt(3) + 7) % 8;
                    }
                    stepCounter++;
                }

                if (!isPos(curPos)) {
                    continue; //   failed to land on deposit: clipped off
                }

                weights[curPos] += pointWeight;
                p++;
                tries = tryNum;
            }
        }

        for (int i = 0; i < cells; i++) {
            if (weights[i] > 0) {
                eventModel.add(i, weights[i]);
            }
        }
    }

    protected boolean isDep(int nextPos) {
        return isPos(nextPos) && weights[nextPos] > 0;
    }

    public Point chooseLocation(final EntropySource eSource) {
        final int freeIndex = eventModel.generate(eSource, true, null);
        final Point point = index2p(freeIndex);

        return point;
    }

    public double getDensity(Point location) {
        return weights[p2index(location)];
    }
}