org.pepsoft.worldpainter.brushes.RotatedBrush Maven / Gradle / Ivy
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.brushes;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.*;
/**
* A brush which can rotate another brush an arbitrary angle around its center. Radius and level are propagated to the
* encapsulated brush.
*
* @author SchmitzP
*/
public final class RotatedBrush extends AbstractBrush {
private RotatedBrush(Brush brush, int degrees) {
super(brush.getName());
this.brush = brush;
this.degrees = degrees;
radius = brush.getRadius();
level = brush.getLevel();
cacheAllStrengths();
}
public Brush getBrush() {
return brush;
}
public int getDegrees() {
return degrees;
}
public void setDegrees(int degrees) {
if (degrees != this.degrees) {
this.degrees = degrees;
cacheAllStrengths();
}
}
@Override
public int getRadius() {
return radius;
}
@Override
public void setRadius(int radius) {
if (radius != this.radius) {
this.radius = radius;
brush.setRadius(radius);
cacheAllStrengths();
}
}
@Override
public int getEffectiveRadius() {
return effectiveRadius;
}
@Override
public float getLevel() {
return level;
}
@Override
public void setLevel(float level) {
if (level != this.level) {
this.level = level;
brush.setLevel(level);
if (fullStrengthCache == null) {
cacheAllStrengths();
}
}
}
@Override
public BrushShape getBrushShape() {
return brush.getBrushShape();
}
@Override
public float getStrength(int dx, int dy) {
final int x = dx + effectiveRadius, y = dy + effectiveRadius;
if ((x < 0) || (x >= effectiveWidth) || (y < 0) || (y >= effectiveHeight)) {
return 0.0f;
} else if (level == 1.0f) {
return fullStrengthCache.getSample(x, y, 0) / 255f;
} else {
return fullStrengthCache.getSample(x, y, 0) / 255f * level;
}
}
@Override
public float getFullStrength(int dx, int dy) {
final int x = dx + effectiveRadius, y = dy + effectiveRadius;
if ((x < 0) || (x >= effectiveWidth) || (y < 0) || (y >= effectiveHeight)) {
return 0.0f;
} else {
return fullStrengthCache.getSample(x, y, 0) / 255f;
}
}
@Override
public RotatedBrush clone() {
RotatedBrush clone = (RotatedBrush) super.clone();
clone.brush = brush.clone();
return clone;
}
private void cacheAllStrengths() {
final int d = radius * 2 + 1;
// Create image from original brush
final byte[] rasterData = new byte[d * d];
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
rasterData[dx + radius + (dy + radius) * d] = (byte) (brush.getFullStrength(dx, dy) * 255);
}
}
final DataBuffer imageDataBuffer = new DataBufferByte(rasterData, d * d);
final Raster raster = Raster.createRaster(new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, d, d, new int[] {255}), imageDataBuffer, new Point(0, 0));
// Rotate image
final double a = degrees / 180d * Math.PI;
AffineTransformOp transformOp = new AffineTransformOp(AffineTransform.getRotateInstance(a), AffineTransformOp.TYPE_BICUBIC);
Rectangle2D transformedBounds = transformOp.getBounds2D(raster);
AffineTransform transform = AffineTransform.getTranslateInstance(-transformedBounds.getX(), -transformedBounds.getY());
transform.rotate(a);
transformOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_BICUBIC);
fullStrengthCache = transformOp.filter(raster, null);
// Calculate effective dimensions
effectiveWidth = fullStrengthCache.getWidth();
effectiveHeight = fullStrengthCache.getHeight();
effectiveRadius = effectiveWidth / 2;
}
/**
* Rotate a brush in the most efficient way possible. If no rotation is
* necessary or applicable, this method returns the original brush. If the
* specified brush is already a rotated brush, a new rotated brush based on
* the original non-rotated brush is returned, to avoid unnecessary double
* rotations.
*
* @param brush The brush to rotate.
* @param degrees The number of degrees to rotate the brush clockwise.
* @return The specified brush, rotated as specified.
*/
public static Brush rotate(Brush brush, int degrees) {
degrees = Math.floorMod(degrees, 360);
if (degrees == 0) {
return brush;
} else if (brush instanceof RotatedBrush) {
int adjustedDegrees = Math.floorMod(((RotatedBrush) brush).degrees + degrees, 360);
if (adjustedDegrees == 0) {
return ((RotatedBrush) brush).brush;
} else {
return new RotatedBrush(((RotatedBrush) brush).brush, adjustedDegrees);
}
} else if ((brush instanceof SymmetricBrush) && ((SymmetricBrush) brush).isRotationallySymmetric()) {
return brush;
} else {
return new RotatedBrush(brush, degrees);
}
}
private Brush brush;
private int radius, effectiveRadius, degrees, effectiveWidth, effectiveHeight;
private float level;
private Raster fullStrengthCache;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy