mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-10 04:38:35 +00:00
Merge pull request #568 from HazelTheWitch/fix-spline-sweep
Fixed NullPointerException in Spline and Sweep brush
This commit is contained in:
@ -59,7 +59,7 @@ public class SplineBrush implements Brush, ResettableTool {
|
||||
return;
|
||||
}
|
||||
int originalSize = numSplines;
|
||||
boolean newPos = this.position == null || !position.equals(this.position);
|
||||
boolean newPos = !position.equals(this.position);
|
||||
this.position = position;
|
||||
if (newPos) {
|
||||
if (positionSets.size() >= MAX_POINTS) {
|
||||
|
@ -8,6 +8,7 @@ import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.math.interpolation.Interpolation;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.RoundedTransform;
|
||||
@ -80,7 +81,7 @@ public class ClipboardSpline extends Spline {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int pasteBlocks(BlockVector3 target, BlockVector3 offset, double angle) throws MaxChangedBlocksException {
|
||||
protected int pasteBlocks(BlockVector3 target, Vector3 offset, double angle) throws MaxChangedBlocksException {
|
||||
RoundedTransform transform = new RoundedTransform(new AffineTransform()
|
||||
.translate(offset)
|
||||
.rotateY(angle));
|
||||
|
@ -21,7 +21,7 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class Spline {
|
||||
|
||||
private BlockVector2 direction = BlockVector2.at(1, 0);
|
||||
private Vector2 direction = Vector2.at(1, 0);
|
||||
private final int nodeCount;
|
||||
|
||||
protected EditSession editSession;
|
||||
@ -77,10 +77,10 @@ public abstract class Spline {
|
||||
* is rotated by that angle to follow the curve slope.
|
||||
* <p>
|
||||
* The default direction is a (1;0) vector (pointing in the positive x-direction).
|
||||
* @param direction A normalized vector representing the horizontal forward direction of the clipboard content
|
||||
* @param direction A vector representing the horizontal forward direction of the clipboard content
|
||||
*/
|
||||
public void setDirection(BlockVector2 direction) {
|
||||
this.direction = direction;
|
||||
public void setDirection(Vector2 direction) {
|
||||
this.direction = direction.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,7 +93,7 @@ public abstract class Spline {
|
||||
* The default direction is a (1;0) vector (pointing in the positive x-direction).
|
||||
* @return A vector representing the horizontal forward direction of the clipboard content
|
||||
*/
|
||||
public BlockVector2 getDirection() {
|
||||
public Vector2 getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
@ -115,6 +115,13 @@ public abstract class Spline {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2 dimensional "cross" product. cross2D(v1, v2) = |v1|*|v2|*sin(theta) or v1 X v2 taking Y to be 0
|
||||
*/
|
||||
private double cross2D(Vector2 v1, Vector2 v2) {
|
||||
return v1.getX() * v2.getZ() - v2.getX() * v1.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste structure at the provided position on the curve. The position will not be position-corrected
|
||||
* but will be passed directly to the interpolation algorithm.
|
||||
@ -127,22 +134,24 @@ public abstract class Spline {
|
||||
Preconditions.checkArgument(position <= 1);
|
||||
|
||||
// Calculate position from spline
|
||||
BlockVector3 target = interpolation.getPosition(position).toBlockPoint();
|
||||
BlockVector3 offset = target.subtract(target.round());
|
||||
target = target.subtract(offset);
|
||||
Vector3 target = interpolation.getPosition(position);
|
||||
BlockVector3 blockTarget = target.toBlockPoint();
|
||||
Vector3 offset = target.subtract(target.floor());
|
||||
|
||||
// Calculate rotation from spline
|
||||
|
||||
Vector3 deriv = interpolation.get1stDerivative(position);
|
||||
Vector2 deriv2D = Vector2.at(deriv.getX(), deriv.getZ()).normalize();
|
||||
double angle = Math.toDegrees(
|
||||
Math.atan2(direction.getZ(), direction.getX()) - Math.atan2(deriv2D.getZ(), deriv2D.getX())
|
||||
-Math.atan2(cross2D(direction, deriv2D), direction.dot(deriv2D))
|
||||
);
|
||||
|
||||
angle = ((angle % 360) + 360) % 360; // Wrap to 360 degrees
|
||||
|
||||
return pasteBlocks(target, offset, angle);
|
||||
return pasteBlocks(blockTarget, offset, angle);
|
||||
}
|
||||
|
||||
protected abstract int pasteBlocks(BlockVector3 target, BlockVector3 offset, double angle) throws MaxChangedBlocksException;
|
||||
protected abstract int pasteBlocks(BlockVector3 target, Vector3 offset, double angle) throws MaxChangedBlocksException;
|
||||
|
||||
private void initSections() {
|
||||
int sectionCount = nodeCount - 1;
|
||||
@ -176,7 +185,15 @@ public abstract class Spline {
|
||||
double flexOffset = flexPosition - previousSection.flexStart;
|
||||
double uniOffset = flexOffset / previousSection.flexLength * previousSection.uniLength;
|
||||
|
||||
return previousSection.uniStart + uniOffset;
|
||||
double finalPosition = previousSection.uniStart + uniOffset;
|
||||
|
||||
//Really rough fix, but fixes a bug with no visual artifacts so it's probably ok?
|
||||
//flexPosition very close to 1 causes outputs very slightly higher than 1 on rare occasions
|
||||
if (finalPosition > 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return finalPosition;
|
||||
}
|
||||
|
||||
private class Section {
|
||||
|
@ -13,11 +13,14 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableVector3;
|
||||
import com.sk89q.worldedit.math.Vector2;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.math.interpolation.Interpolation;
|
||||
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
|
||||
import com.sk89q.worldedit.math.interpolation.Node;
|
||||
import com.sk89q.worldedit.math.interpolation.ReparametrisingInterpolation;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
|
||||
@ -64,7 +67,7 @@ public class SweepBrush implements Brush, ResettableTool {
|
||||
return;
|
||||
}
|
||||
|
||||
Interpolation interpol = new KochanekBartelsInterpolation();
|
||||
Interpolation interpol = new ReparametrisingInterpolation(new KochanekBartelsInterpolation());
|
||||
List<Node> nodes = positions.stream().map(v -> {
|
||||
Node n = new Node(v.toVector3());
|
||||
n.setTension(tension);
|
||||
@ -82,37 +85,26 @@ public class SweepBrush implements Brush, ResettableTool {
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
|
||||
BlockVector3 dimensions = clipboard.getDimensions();
|
||||
AffineTransform transform = new AffineTransform();
|
||||
if (dimensions.getBlockX() > dimensions.getBlockZ()) {
|
||||
transform = transform.rotateY(90);
|
||||
}
|
||||
double quality = Math.max(dimensions.getBlockX(), dimensions.getBlockZ());
|
||||
|
||||
AffineTransform transform = new AffineTransform();
|
||||
|
||||
ClipboardSpline spline = new ClipboardSpline(editSession, holder, interpol, transform, nodes.size());
|
||||
|
||||
if (dimensions.getBlockX() > dimensions.getBlockZ()) {
|
||||
spline.setDirection(Vector2.at(0, 1));
|
||||
}
|
||||
|
||||
switch (copies) {
|
||||
case 1: {
|
||||
spline.pastePosition(0D);
|
||||
break;
|
||||
}
|
||||
case -1: {
|
||||
double splineLength = interpol.arcLength(0D, 1D);
|
||||
double blockDistance = 1d / splineLength;
|
||||
double step = blockDistance / quality;
|
||||
double accumulation = 0;
|
||||
MutableVector3 last = new MutableVector3(0, 0, 0);
|
||||
for (double pos = 0D; pos <= 1D; pos += step) {
|
||||
Vector3 gradient = interpol.get1stDerivative(pos);
|
||||
double dist = MathMan.sqrtApprox(last.distanceSq(gradient));
|
||||
last.mutX(gradient.getX());
|
||||
last.mutY(gradient.getY());
|
||||
last.mutZ(gradient.getZ());
|
||||
double change = dist * step;
|
||||
// Accumulation is arbitrary, but much faster than calculation overlapping regions
|
||||
if ((accumulation += change + step * 2) > blockDistance) {
|
||||
accumulation -= blockDistance;
|
||||
spline.pastePosition(pos);
|
||||
}
|
||||
double length = interpol.arcLength(0, 1);
|
||||
double step = 1 / (length * quality);
|
||||
for (double pos = 0; pos <= 1; pos += step) {
|
||||
spline.pastePosition(pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -200,6 +200,10 @@ public abstract class DFSVisitor implements Operation {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Node other = (Node) obj;
|
||||
return other.x == x && other.z == z && other.y == y;
|
||||
}
|
||||
|
Reference in New Issue
Block a user