mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-25 03:55:35 +01:00
Add surface spline
This commit is contained in:
parent
b20120a1f2
commit
147cfeed10
@ -18,7 +18,6 @@ import com.sk89q.worldedit.function.mask.MaskIntersection;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.interpolation.Node;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -125,12 +124,6 @@ public class SplineBrush implements Brush {
|
||||
n.setContinuity(continuity);
|
||||
nodes.add(n);
|
||||
}
|
||||
|
||||
Vector up = new Vector(0, 1, 0);
|
||||
AffineTransform transform = new AffineTransform();
|
||||
|
||||
// TODO index offset based on transform
|
||||
|
||||
int samples = numSplines;
|
||||
for (int i = 0; i < numSplines; i++) {
|
||||
List<Vector> currentSpline = new ArrayList<>();
|
||||
|
@ -0,0 +1,82 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
|
||||
import com.sk89q.worldedit.math.interpolation.Node;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SurfaceSpline implements Brush {
|
||||
final double tension, bias,continuity, quality;
|
||||
|
||||
public SurfaceSpline(final double tension, final double bias, final double continuity, final double quality) {
|
||||
this.tension = tension;
|
||||
this.bias = bias;
|
||||
this.continuity = continuity;
|
||||
this.quality = quality;
|
||||
}
|
||||
|
||||
private ArrayList<Vector> path = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void build(EditSession editSession, Vector pos, Pattern pattern, double radius) throws MaxChangedBlocksException {
|
||||
int maxY = editSession.getMaxY();
|
||||
if (path.isEmpty() || !pos.equals(path.get(path.size() - 1))) {
|
||||
int max = editSession.getNearestSurfaceTerrainBlock(pos.getBlockX(), pos.getBlockZ(), pos.getBlockY(), 0, editSession.getMaxY());
|
||||
pos.mutY(max);
|
||||
path.add(pos);
|
||||
editSession.getPlayer().sendMessage(BBC.getPrefix() + BBC.BRUSH_SPLINE_PRIMARY_2.s());
|
||||
} else{
|
||||
LocalBlockVectorSet vset = new LocalBlockVectorSet();
|
||||
final List<Node> nodes = new ArrayList<>(path.size());
|
||||
final KochanekBartelsInterpolation interpol = new KochanekBartelsInterpolation();
|
||||
|
||||
for (final Vector nodevector : path) {
|
||||
final Node n = new Node(nodevector);
|
||||
n.setTension(tension);
|
||||
n.setBias(bias);
|
||||
n.setContinuity(continuity);
|
||||
nodes.add(n);
|
||||
}
|
||||
interpol.setNodes(nodes);
|
||||
final double splinelength = interpol.arcLength(0, 1);
|
||||
for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) {
|
||||
final Vector tipv = interpol.getPosition(loop);
|
||||
final int tipx = (int) Math.round(tipv.getX());
|
||||
final int tipz = (int) tipv.getZ();
|
||||
int tipy = (int) Math.round(tipv.getY());
|
||||
tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY);
|
||||
if (radius == 0) {
|
||||
editSession.setBlock(tipx, tipy, tipz, pattern.next(tipx, tipy, tipz));
|
||||
} else {
|
||||
vset.add(tipx, tipy, tipz);
|
||||
}
|
||||
}
|
||||
if (radius != 0) {
|
||||
double radius2 = (radius * radius);
|
||||
LocalBlockVectorSet newSet = new LocalBlockVectorSet();
|
||||
final int ceilrad = (int) Math.ceil(radius);
|
||||
for (final Vector v : vset) {
|
||||
final int tipx = v.getBlockX(), tipy = v.getBlockY(), tipz = v.getBlockZ();
|
||||
for (int loopx = tipx - ceilrad; loopx <= (tipx + ceilrad); loopx++) {
|
||||
for (int loopz = tipz - ceilrad; loopz <= (tipz + ceilrad); loopz++) {
|
||||
if (MathMan.hypot2(loopx - tipx, 0, loopz - tipz) <= radius2) {
|
||||
int y = editSession.getNearestSurfaceTerrainBlock(loopx, loopz, v.getBlockY(), 0, maxY);
|
||||
newSet.add(loopx, y, loopz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
editSession.setBlocks(newSet, pattern);
|
||||
}
|
||||
editSession.getPlayer().sendMessage(BBC.getPrefix() + BBC.BRUSH_SPLINE_SECONDARY.s());
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,6 @@ import java.util.UUID;
|
||||
* - Uses an auto closable RandomAccessFile for getting / setting id / data
|
||||
* - I don't know how to reduce nbt / entities to O(2) complexity, so it is stored in memory.
|
||||
*
|
||||
* TODO load on join
|
||||
*/
|
||||
public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
|
||||
|
@ -43,6 +43,22 @@ public class MathMan {
|
||||
253, 254, 254, 255
|
||||
};
|
||||
|
||||
public static double hypot(final double... pars) {
|
||||
double sum = 0;
|
||||
for (final double d : pars) {
|
||||
sum += Math.pow(d, 2);
|
||||
}
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
public static double hypot2(final double... pars) {
|
||||
double sum = 0;
|
||||
for (final double d : pars) {
|
||||
sum += Math.pow(d, 2);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static final int wrap(int value, int min, int max) {
|
||||
if (max < min) {
|
||||
return value;
|
||||
|
@ -58,6 +58,7 @@ import com.boydti.fawe.object.progress.DefaultProgressTracker;
|
||||
import com.boydti.fawe.object.visitor.FastChunkIterator;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.boydti.fawe.util.MaskTraverser;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
@ -1142,7 +1143,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private int setBlocks(final Set<Vector> vset, final Pattern pattern) throws MaxChangedBlocksException {
|
||||
public int setBlocks(final Set<Vector> vset, final Pattern pattern) throws MaxChangedBlocksException {
|
||||
RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(extent, pattern), this);
|
||||
Operations.completeBlindly(visitor);
|
||||
changes += visitor.getAffected();
|
||||
@ -1713,7 +1714,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
}
|
||||
|
||||
// public int replaceBlocks(final Region region, final Mask mask, final BaseBlock block) throws MaxChangedBlocksException {
|
||||
// TODO
|
||||
// TODO fast replace
|
||||
// }
|
||||
|
||||
/**
|
||||
@ -2663,7 +2664,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
for (int y = basePosition.getBlockY(); y >= (basePosition.getBlockY() - 10); --y) {
|
||||
final int t = getLazyBlock(x, y, z).getType();
|
||||
if ((t == BlockID.GRASS) || (t == BlockID.DIRT)) {
|
||||
treeGenerator.generate(EditSession.this, new Vector(x, y + 1, z));
|
||||
treeGenerator.generate(EditSession.this, mutable.setComponents(x, y + 1, z));
|
||||
break;
|
||||
} else if (t == BlockID.SNOW) {
|
||||
setBlock(x, y, z, nullBlock);
|
||||
@ -2810,7 +2811,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
final ArbitraryShape shape = new ArbitraryShape(region) {
|
||||
@Override
|
||||
public BaseBlock getMaterial(final int x, final int y, final int z, final BaseBlock defaultMaterial) {
|
||||
final Vector current = new Vector(x, y, z);
|
||||
//TODO Optimize - avoid vector creation (math)
|
||||
final Vector current = mutable.setComponents(x, y, z);
|
||||
environment.setCurrentBlock(current);
|
||||
final Vector scaled = current.subtract(zero).divide(unit);
|
||||
|
||||
@ -2973,7 +2975,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
*/
|
||||
public int drawLine(final Pattern pattern, final Vector pos1, final Vector pos2, final double radius, final boolean filled, boolean flat) throws MaxChangedBlocksException {
|
||||
|
||||
Set vset = new LocalBlockVectorSet();
|
||||
LocalBlockVectorSet vset = new LocalBlockVectorSet();
|
||||
boolean notdrawn = true;
|
||||
|
||||
final int x1 = pos1.getBlockX(), y1 = pos1.getBlockY(), z1 = pos1.getBlockZ();
|
||||
@ -2982,7 +2984,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
final int dx = Math.abs(x2 - x1), dy = Math.abs(y2 - y1), dz = Math.abs(z2 - z1);
|
||||
|
||||
if ((dx + dy + dz) == 0) {
|
||||
vset.add(new Vector(tipx, tipy, tipz));
|
||||
vset.add(tipx, tipy, tipz);
|
||||
notdrawn = false;
|
||||
}
|
||||
|
||||
@ -2991,7 +2993,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
tipx = x1 + (domstep * ((x2 - x1) > 0 ? 1 : -1));
|
||||
tipy = (int) Math.round(y1 + (((domstep * ((double) dy)) / (dx)) * ((y2 - y1) > 0 ? 1 : -1)));
|
||||
tipz = (int) Math.round(z1 + (((domstep * ((double) dz)) / (dx)) * ((z2 - z1) > 0 ? 1 : -1)));
|
||||
vset.add(new Vector(tipx, tipy, tipz));
|
||||
vset.add(tipx, tipy, tipz);
|
||||
}
|
||||
notdrawn = false;
|
||||
}
|
||||
@ -3002,7 +3004,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
tipx = (int) Math.round(x1 + (((domstep * ((double) dx)) / (dy)) * ((x2 - x1) > 0 ? 1 : -1)));
|
||||
tipz = (int) Math.round(z1 + (((domstep * ((double) dz)) / (dy)) * ((z2 - z1) > 0 ? 1 : -1)));
|
||||
|
||||
vset.add(new Vector(tipx, tipy, tipz));
|
||||
vset.add(tipx, tipy, tipz);
|
||||
}
|
||||
notdrawn = false;
|
||||
}
|
||||
@ -3012,21 +3014,22 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
tipz = z1 + (domstep * ((z2 - z1) > 0 ? 1 : -1));
|
||||
tipy = (int) Math.round(y1 + (((domstep * ((double) dy)) / (dz)) * ((y2 - y1) > 0 ? 1 : -1)));
|
||||
tipx = (int) Math.round(x1 + (((domstep * ((double) dx)) / (dz)) * ((x2 - x1) > 0 ? 1 : -1)));
|
||||
vset.add(new Vector(tipx, tipy, tipz));
|
||||
vset.add(tipx, tipy, tipz);
|
||||
}
|
||||
}
|
||||
Set<Vector> newVset;
|
||||
if (flat) {
|
||||
vset = this.getStretched(vset, radius);
|
||||
newVset = this.getStretched(vset, radius);
|
||||
if (!filled) {
|
||||
vset = this.getOutline(vset);
|
||||
newVset = this.getOutline(newVset);
|
||||
}
|
||||
} else {
|
||||
vset = this.getBallooned(vset, radius);
|
||||
newVset = this.getBallooned(vset, radius);
|
||||
if (!filled) {
|
||||
vset = this.getHollowed(vset);
|
||||
newVset = this.getHollowed(newVset);
|
||||
}
|
||||
}
|
||||
return this.setBlocks(vset, pattern);
|
||||
return this.setBlocks(newVset, pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3044,10 +3047,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
* @return number of blocks affected
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
*/
|
||||
public int drawSpline(final Pattern pattern, final List<Vector> nodevectors, final double tension, final double bias, final double continuity, final double quality, final double radius,
|
||||
final boolean filled) throws MaxChangedBlocksException {
|
||||
|
||||
Set vset = new LocalBlockVectorSet();
|
||||
public int drawSpline(final Pattern pattern, final List<Vector> nodevectors, final double tension, final double bias, final double continuity, final double quality, final double radius, final boolean filled) throws MaxChangedBlocksException {
|
||||
LocalBlockVectorSet vset = new LocalBlockVectorSet();
|
||||
final List<Node> nodes = new ArrayList<Node>(nodevectors.size());
|
||||
|
||||
final KochanekBartelsInterpolation interpol = new KochanekBartelsInterpolation();
|
||||
@ -3070,40 +3071,33 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
if (radius == 0) {
|
||||
setBlock(tipx, tipy, tipz, pattern.next(tipx, tipy, tipz));
|
||||
} else {
|
||||
vset.add(new Vector(tipx, tipy, tipz));
|
||||
vset.add(tipx, tipy, tipz);
|
||||
}
|
||||
}
|
||||
Set<Vector> newVset;
|
||||
if (radius != 0) {
|
||||
vset = this.getBallooned(vset, radius);
|
||||
newVset = this.getBallooned(vset, radius);
|
||||
if (!filled) {
|
||||
vset = this.getHollowed(vset);
|
||||
newVset = this.getHollowed(newVset);
|
||||
}
|
||||
return this.setBlocks(vset, pattern);
|
||||
return this.setBlocks(newVset, pattern);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
private double hypot(final double... pars) {
|
||||
double sum = 0;
|
||||
for (final double d : pars) {
|
||||
sum += Math.pow(d, 2);
|
||||
}
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
private Set<Vector> getBallooned(final Set<Vector> vset, final double radius) {
|
||||
if (radius < 1) {
|
||||
return vset;
|
||||
}
|
||||
final Set returnset = new LocalBlockVectorSet();
|
||||
final LocalBlockVectorSet returnset = new LocalBlockVectorSet();
|
||||
final int ceilrad = (int) Math.ceil(radius);
|
||||
for (final Vector v : vset) {
|
||||
final int tipx = v.getBlockX(), tipy = v.getBlockY(), tipz = v.getBlockZ();
|
||||
for (int loopx = tipx - ceilrad; loopx <= (tipx + ceilrad); loopx++) {
|
||||
for (int loopy = tipy - ceilrad; loopy <= (tipy + ceilrad); loopy++) {
|
||||
for (int loopz = tipz - ceilrad; loopz <= (tipz + ceilrad); loopz++) {
|
||||
if (this.hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) {
|
||||
returnset.add(new Vector(loopx, loopy, loopz));
|
||||
if (MathMan.hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) {
|
||||
returnset.add(loopx, loopy, loopz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3112,18 +3106,18 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
return returnset;
|
||||
}
|
||||
|
||||
private Set<Vector> getStretched(final Set<Vector> vset, final double radius) {
|
||||
public Set<Vector> getStretched(final Set<Vector> vset, final double radius) {
|
||||
if (radius < 1) {
|
||||
return vset;
|
||||
}
|
||||
final Set returnset = new LocalBlockVectorSet();
|
||||
final LocalBlockVectorSet returnset = new LocalBlockVectorSet();
|
||||
final int ceilrad = (int) Math.ceil(radius);
|
||||
for (final Vector v : vset) {
|
||||
final int tipx = v.getBlockX(), tipy = v.getBlockY(), tipz = v.getBlockZ();
|
||||
for (int loopx = tipx - ceilrad; loopx <= (tipx + ceilrad); loopx++) {
|
||||
for (int loopz = tipz - ceilrad; loopz <= (tipz + ceilrad); loopz++) {
|
||||
if (this.hypot(loopx - tipx, 0, loopz - tipz) <= radius) {
|
||||
returnset.add(new Vector(loopx, v.getY(), loopz));
|
||||
if (MathMan.hypot(loopx - tipx, 0, loopz - tipz) <= radius) {
|
||||
returnset.add(loopx, v.getBlockY(), loopz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3131,8 +3125,9 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
return returnset;
|
||||
}
|
||||
|
||||
private Set<Vector> getOutline(final Set<Vector> vset) {
|
||||
final Set returnset = new LocalBlockVectorSet();
|
||||
public Set<Vector> getOutline(final Set<Vector> vset) {
|
||||
// TODO optimize - vset instanceof LocalBlockVectorSet -> avoid Vector creation
|
||||
final LocalBlockVectorSet returnset = new LocalBlockVectorSet();
|
||||
for (final Vector v : vset) {
|
||||
final double x = v.getX(), y = v.getY(), z = v.getZ();
|
||||
if (!(vset.contains(new Vector(x + 1, y, z))
|
||||
@ -3144,7 +3139,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
return returnset;
|
||||
}
|
||||
|
||||
private Set<Vector> getHollowed(final Set<Vector> vset) {
|
||||
public Set<Vector> getHollowed(final Set<Vector> vset) {
|
||||
//TODO Optimize - avoid vector creation
|
||||
final Set returnset = new LocalBlockVectorSet();
|
||||
for (final Vector v : vset) {
|
||||
final double x = v.getX(), y = v.getY(), z = v.getZ();
|
||||
@ -3159,7 +3155,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
return returnset;
|
||||
}
|
||||
|
||||
private void recurseHollow(final Region region, final BlockVector origin, final Set<BlockVector> outside) {
|
||||
public void recurseHollow(final Region region, final BlockVector origin, final Set<BlockVector> outside) {
|
||||
//TODO Optimize - avoid vector creation
|
||||
final ArrayDeque<BlockVector> queue = new ArrayDeque<BlockVector>();
|
||||
queue.addLast(origin);
|
||||
|
||||
@ -3283,6 +3280,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
}
|
||||
|
||||
public boolean regenerate(final Region region, final BaseBiome biome, final Long seed) {
|
||||
//TODO Optimize - avoid Vector2D creation (make mutable)
|
||||
final FaweQueue queue = this.getQueue();
|
||||
queue.setChangeTask(null);
|
||||
final FaweChangeSet fcs = (FaweChangeSet) this.getChangeSet();
|
||||
|
@ -41,6 +41,7 @@ import com.boydti.fawe.object.brush.ShatterBrush;
|
||||
import com.boydti.fawe.object.brush.SplatterBrush;
|
||||
import com.boydti.fawe.object.brush.SplineBrush;
|
||||
import com.boydti.fawe.object.brush.StencilBrush;
|
||||
import com.boydti.fawe.object.brush.SurfaceSpline;
|
||||
import com.boydti.fawe.object.brush.TargetMode;
|
||||
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
||||
import com.boydti.fawe.object.brush.scroll.ScrollClipboard;
|
||||
@ -407,6 +408,26 @@ public class BrushCommands {
|
||||
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE.f(radius));
|
||||
}
|
||||
|
||||
// final double tension, final double bias, final double continuity, final double quality
|
||||
|
||||
@Command(
|
||||
aliases = { "sspl", "sspline", "surfacespline" },
|
||||
usage = "<pattern> [size] [tension] [bias] [continuity] [quality]",
|
||||
desc = "Draws a spline on the surface",
|
||||
help = "Chooses the surface spline brush",
|
||||
min = 0,
|
||||
max = 2
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.surfacespline") // 0, 0, 0, 10, 0,
|
||||
public void surfaceSpline(Player player, LocalSession session, Pattern fill, @Optional("0") double radius, @Optional("0") double tension, @Optional("0") double bias, @Optional("0") double continuity, @Optional("10") double quality) throws WorldEditException {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
BrushTool tool = session.getBrushTool(player);
|
||||
tool.setFill(fill);
|
||||
tool.setSize(radius);
|
||||
tool.setBrush(new SurfaceSpline(tension, bias, continuity, quality), "worldedit.brush.spline", player);
|
||||
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE.f(radius));
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "sphere", "s" },
|
||||
usage = "<pattern> [radius]",
|
||||
|
@ -148,7 +148,6 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
try {
|
||||
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(context.getActor(), context.requireWorld().getWorldData(), location, true);
|
||||
if (clipboards == null) {
|
||||
System.out.println("NULL!");
|
||||
throw new InputParseException("#fullcopy:<source>");
|
||||
}
|
||||
boolean random = split2.length == 3 && split2[2].equalsIgnoreCase("true");
|
||||
|
Loading…
Reference in New Issue
Block a user