org.pepsoft.worldpainter.brushes.SymmetricBrush Maven / Gradle / Ivy
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.brushes;
import org.pepsoft.util.ObjectUtils;
/**
* An object which calculates brush strengths for simple mathematical brushes,
* which must be symmetric in both the x and y axes (so that only one quadrant
* of the brush needs to be calculated).
*
* @author pepijn
*/
public abstract class SymmetricBrush extends AbstractBrush {
public SymmetricBrush(String name, BrushShape brushShape, boolean rotationallySymmetric) {
super(name);
this.brushShape = brushShape;
this.rotationallySymmetric = rotationallySymmetric;
cacheStrengths();
}
@Override
public BrushShape getBrushShape() {
return brushShape;
}
@Override
public int getRadius() {
return radius;
}
@Override
public void setRadius(int radius) {
if (radius != this.radius) {
this.radius = radius;
cacheStrengths();
}
}
@Override
public float getLevel() {
return level;
}
@Override
public void setLevel(float level) {
if (level != this.level) {
this.level = level;
cacheStrengths();
}
}
public final boolean isRotationallySymmetric() {
return rotationallySymmetric;
}
@Override
public final float getStrength(int dx, int dy) {
return strengthCache[Math.abs(dx)][Math.abs(dy)];
}
@Override
public final float getFullStrength(int dx, int dy) {
return fullStrengthCache[Math.abs(dx)][Math.abs(dy)];
}
@Override
public String toString() {
return getName() + " (radius=" + radius + ", brushShape=" + brushShape + ", level=" + level + ')';
}
@Override
public SymmetricBrush clone() {
SymmetricBrush clone = (SymmetricBrush) super.clone();
if (strengthCache != null) {
clone.strengthCache = ObjectUtils.clone(strengthCache);
}
if (fullStrengthCache != null) {
if (fullStrengthCache == strengthCache) {
clone.fullStrengthCache = clone.strengthCache;
} else {
clone.fullStrengthCache = ObjectUtils.clone(fullStrengthCache);
}
}
return clone;
}
protected abstract float calcStrength(int dx, int dy);
private void cacheStrengths() {
if ((radius != cachedRadius) || (level != cachedLevel)) {
// No need to allocate a new array if there is one already and the
// data will fit in it:
if ((strengthCache == null) || (strengthCache.length < (radius + 1))) {
strengthCache = new float[radius + 1][radius + 1];
}
// Only update the full strength cache if necessary
if (radius != cachedRadius) {
// No need to allocate a new array if there is one already and the
// data will fit in it:
if ((fullStrengthCache == null) || (fullStrengthCache.length < (radius + 1))) {
fullStrengthCache = new float[radius + 1][radius + 1];
}
for (int dx = 0; dx <= radius; dx++) {
for (int dy = 0; dy <= radius; dy++) {
float strength = calcStrength(dx, dy);
strengthCache[dx][dy] = strength * level;
fullStrengthCache[dx][dy] = strength;
}
}
} else {
for (int dx = 0; dx <= radius; dx++) {
for (int dy = 0; dy <= radius; dy++) {
strengthCache[dx][dy] = calcStrength(dx, dy) * level;
}
}
}
cachedRadius = radius;
cachedLevel = level;
}
}
protected final boolean rotationallySymmetric;
protected final BrushShape brushShape;
private int radius, cachedRadius = -1;
private float[][] strengthCache, fullStrengthCache;
private float level = 1.0f, cachedLevel = -1.0f;
public static final SymmetricBrush CONSTANT_CIRCLE = new RadialBrush("Constant Circle", BrushShape.CIRCLE, true) {
@Override
protected float calcStrength(float dr) {
return 1.0f;
}
};
public static final SymmetricBrush CONSTANT_SQUARE = new RadialBrush("Constant Square", BrushShape.SQUARE, false) {
@Override
protected float calcStrength(float dr) {
return 1.0f;
}
};
public static final SymmetricBrush LINEAR_CIRCLE = new RadialBrush("Linear Circle", BrushShape.CIRCLE, true) {
@Override
protected float calcStrength(float dr) {
return 1.0f - dr;
}
};
public static final SymmetricBrush LINEAR_SQUARE = new RadialBrush("Linear Square", BrushShape.SQUARE, false) {
@Override
protected float calcStrength(float dr) {
return 1.0f - dr;
}
};
public static final SymmetricBrush COSINE_CIRCLE = new RadialBrush("Sine Circle", BrushShape.CIRCLE, true) {
@Override
protected float calcStrength(float dr) {
return (float) Math.cos(dr * Math.PI) / 2 + 0.5f;
}
};
public static final SymmetricBrush COSINE_SQUARE = new RadialBrush("Sine Square", BrushShape.SQUARE, false) {
@Override
protected float calcStrength(float dr) {
return (float) Math.cos(dr * Math.PI) / 2 + 0.5f;
}
};
public static final SymmetricBrush PLATEAU_CIRCLE = new RadialBrush("Plateau Circle", BrushShape.CIRCLE, true) {
@Override
protected float calcStrength(float dr) {
if (dr <= 0.5f) {
return 1.0f;
} else {
return (float) Math.cos((dr - 0.5f) * TWO_PI) / 2 + 0.5f;
}
}
};
public static final SymmetricBrush PLATEAU_SQUARE = new RadialBrush("Plateau Square", BrushShape.SQUARE, false) {
@Override
protected float calcStrength(float dr) {
if (dr <= 0.5f) {
return 1.0f;
} else {
return (float) Math.cos((dr - 0.5f) * TWO_PI) / 2 + 0.5f;
}
}
};
public static final SymmetricBrush SPIKE_CIRCLE = new RadialBrush("Spike Circle", BrushShape.CIRCLE, true) {
@Override
protected float calcStrength(float dr) {
return (1.0f - dr) * (1.0f - dr);
}
};
public static final SymmetricBrush SPIKE_SQUARE = new RadialBrush("Spike Square", BrushShape.SQUARE, false) {
@Override
protected float calcStrength(float dr) {
return (1.0f - dr) * (1.0f - dr);
}
};
public static final SymmetricBrush DOME_CIRCLE = new RadialBrush("Dome Circle", BrushShape.CIRCLE, true) {
@Override
protected float calcStrength(float dr) {
return (float) Math.sqrt(1 - dr * dr);
}
};
public static final SymmetricBrush DOME_SQUARE = new RadialBrush("Dome Square", BrushShape.SQUARE, false) {
@Override
protected float calcStrength(float dr) {
return (float) Math.sqrt(1 - dr * dr);
}
};
private static final float TWO_PI = (float) (Math.PI * 2);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy