Skip to content

Commit 123d644

Browse files
Daniel Naylorgabizou
authored andcommitted
Add Transformation for positional transformations
Highly useful for rotations and other positional transformations across origins. Can be applied for both block positions and floating point positions, such as for entities. Signed-off-by: Gabriel Harris-Rouquette <[email protected]>
1 parent 9536969 commit 123d644

File tree

4 files changed

+267
-16
lines changed

4 files changed

+267
-16
lines changed

src/main/java/org/spongepowered/api/util/rotation/Rotation.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package org.spongepowered.api.util.rotation;
2626

2727
import org.spongepowered.api.registry.DefaultedRegistryValue;
28+
import org.spongepowered.api.util.Angle;
2829
import org.spongepowered.api.util.annotation.CatalogedBy;
2930

3031
@CatalogedBy(Rotations.class)
@@ -35,8 +36,8 @@ public interface Rotation extends DefaultedRegistryValue {
3536
/**
3637
* Gets the the rotation in degrees always in clockwise order.
3738
*
38-
* @return The rotation in degrees
39+
* @return The rotation
3940
*/
40-
int angle();
41+
Angle angle();
4142

4243
}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* This file is part of SpongeAPI, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package org.spongepowered.api.util.transformation;
26+
27+
import org.spongepowered.api.Sponge;
28+
import org.spongepowered.api.util.Axis;
29+
import org.spongepowered.api.util.ResettableBuilder;
30+
import org.spongepowered.api.util.rotation.Rotation;
31+
import org.spongepowered.api.util.rotation.Rotations;
32+
import org.spongepowered.math.matrix.Matrix4d;
33+
import org.spongepowered.math.vector.Vector3d;
34+
35+
/**
36+
* Performs spacial transformations on position and direction
37+
* {@link Vector3d}s, for general use in block transformations.
38+
*/
39+
public interface Transformation {
40+
41+
/**
42+
* Gets a {@link Transformation.Builder} for creating transformations.
43+
*
44+
* @return A builder
45+
*/
46+
static Transformation.Builder builder() {
47+
return Sponge.game().builderProvider().provide(Transformation.Builder.class);
48+
}
49+
50+
/**
51+
* Transforms a {@link Vector3d} that represents a position based on the
52+
* transformation this object represents.
53+
*
54+
* @param original The position vector to transform
55+
* @return The transformed position vector
56+
*/
57+
Vector3d transformPosition(Vector3d original);
58+
59+
/**
60+
* Transforms a {@link Vector3d} that represents a direction based on the
61+
* transformation this object represents.
62+
*
63+
* <p>Specifically, this transformation will not apply any translational
64+
* transformations.</p>
65+
*
66+
* @param originalDirection The direction vector to transform
67+
* @return The transformed direction vector
68+
*/
69+
Vector3d transformDirection(Vector3d originalDirection);
70+
71+
/**
72+
* Gets the {@link Matrix4d matrix} used to perform this transformation
73+
* on position vectors.
74+
*
75+
* @return The {@link Matrix4d}
76+
*/
77+
Matrix4d positionTransformationMatrix();
78+
79+
/**
80+
* Gets the {@link Matrix4d matrix} used to perform this transformation
81+
* on direction vectors.
82+
*
83+
* @return The {@link Matrix4d}
84+
*/
85+
Matrix4d directionTransformationMatrix();
86+
87+
/**
88+
* Gets the origin of the {@linkplain #positionTransformationMatrix()
89+
* position transformation matrix}.
90+
*
91+
* @return The origin of the position transformations
92+
*/
93+
Vector3d origin();
94+
95+
/**
96+
* Gets the {@link Rotation} around the y-axis
97+
*
98+
* @return The {@link Rotation}
99+
*/
100+
Rotation rotation();
101+
102+
/**
103+
* Returns whether this transformation results in mirroring in the
104+
* direction of the provided axis.
105+
*
106+
* <p>This represents any mirroring that would need to occur
107+
* <strong>after</strong> any rotation has occurred. If you require
108+
* knowing what the mirror state would be pre-rotation, use
109+
* {@link #initialMirror(Axis)} instead.</p>
110+
*
111+
* @param axis The {@link Axis}
112+
* @return true if so
113+
*/
114+
boolean mirror(Axis axis);
115+
116+
/**
117+
* Returns the direction of mirroring in this transformation, if
118+
* mirroring was performed before rotation, at the point before
119+
* the mirroring occurs. The axis is in the direction of the
120+
* mirroring.
121+
*
122+
* <p>Unlike {@link #mirror(Axis)}, which provides a view to
123+
* the direction(s) of mirroring after all transformations have
124+
* taken place, this method returns the direction of mirroring
125+
* <strong>before any rotation has taken place</strong>, such
126+
* that if the {@link #rotation()} was set to
127+
* {@link Rotations#NONE}, this would be the direction of
128+
* mirroring.</p>
129+
*
130+
* @param axis The {@link Axis}
131+
* @return true if so
132+
*/
133+
boolean initialMirror(Axis axis);
134+
135+
/**
136+
* Gets the {@link Transformation} that reverses this transformation.
137+
*
138+
* @return The inverse transformation
139+
*/
140+
Transformation inverse();
141+
142+
/**
143+
* If this is {@code true}, then this transformation will attempt to round
144+
* the result to reduce the effects of machine precision, which may be
145+
* particularly useful for those who expect integer values.
146+
*
147+
* <p>The rounding should be on the order of 15 decimal places,
148+
* though other implementations may choose more sophisticated rounding.</p>
149+
*
150+
* @return Whether the result will have minor rounding applied.
151+
*/
152+
boolean performsRounding();
153+
154+
/**
155+
* Creates a {@link Builder} that represents this transformation.
156+
*
157+
* @return The builder.
158+
*/
159+
Builder toBuilder();
160+
161+
/**
162+
* Creates {@link Transformation transformations}.
163+
*
164+
* <p>Apart from the {@link #origin(Vector3d) origin} transformation, all
165+
* actions will be performed in the order specified in the builder. Thus,
166+
* a translation then a rotation will not produce the same results as
167+
* the reverse.</p>
168+
*/
169+
interface Builder extends ResettableBuilder<Transformation, Builder> {
170+
171+
/**
172+
* Specifies the origin for position transformations.
173+
*
174+
* <p>This is a special transform in that this translation is performed
175+
* before the rest of the transformations are made. Once all
176+
* transformations are performed, this transformation is undone. This
177+
* is especially useful if you are only transforming around a given
178+
* origin which is not at (0, 0, 0), as the rotation will be performed
179+
* around this origin instead.</p>
180+
*
181+
* <p>This does not affect
182+
* {@link Transformation#transformDirection(Vector3d)}</p>
183+
*
184+
* @param origin The origin to transform around
185+
* @return This builder, for chaining
186+
*/
187+
Builder origin(Vector3d origin);
188+
189+
/**
190+
* Performs a rotation about the provided {@link Axis} around the given
191+
* {@link #origin(Vector3d) origin} around the {@link Axis#Y y-axis}.
192+
*
193+
* @param rotation The {@link Rotation} to perform
194+
* @return This builder, for chaining
195+
*/
196+
Builder rotate(Rotation rotation);
197+
198+
/**
199+
* Performs a reflection of -1 in the direction of the given
200+
* {@link Axis}, where the plane from which scaling is performed is
201+
* normal to this axis and contains the {@link #origin(Vector3d)}.
202+
*
203+
* <p>For example, for a point (1, 2, 3), using this transformation
204+
* in the direction the x axis where the origin is at (0, 0, 0) will
205+
* result in a transformation to (-1, 2, 3).</p>
206+
*
207+
* <p>This action is effectively a scaling of -1 in the axis
208+
* direction.</p>
209+
*
210+
* @param axis The axis that represents the direction of scaling
211+
* @return This builder, for chaining
212+
*/
213+
Builder mirror(Axis axis);
214+
215+
/**
216+
* Performs a simple additive translation of a position {@link Vector3d}
217+
* by this supplied vector.
218+
*
219+
* <p>This does not affect
220+
* {@link Transformation#transformDirection(Vector3d)}</p>
221+
*
222+
* @param translate The translation
223+
* @return This builder, for chaining
224+
*/
225+
Builder translate(Vector3d translate);
226+
227+
/**
228+
* Attempts to round the result to attempt to compensate for
229+
* machine precision. Defaults to {@code true}.
230+
*
231+
* @see #performsRounding()
232+
*
233+
* @param round Whether to perform rounding
234+
* @return This builder, for chaining
235+
*/
236+
Builder performRounding(boolean round);
237+
238+
/**
239+
* Builds a {@link Transformation}
240+
*
241+
* @return A {@link Transformation}
242+
*/
243+
Transformation build();
244+
245+
}
246+
247+
}

src/main/java/org/spongepowered/api/world/volume/archetype/ArchetypeVolume.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,12 @@
2525
package org.spongepowered.api.world.volume.archetype;
2626

2727
import org.spongepowered.api.Sponge;
28-
import org.spongepowered.api.block.BlockType;
2928
import org.spongepowered.api.event.CauseStackManager;
3029
import org.spongepowered.api.event.EventContextKeys;
3130
import org.spongepowered.api.event.cause.entity.SpawnType;
32-
import org.spongepowered.api.registry.Registry;
33-
import org.spongepowered.api.registry.RegistryTypes;
31+
import org.spongepowered.api.util.mirror.Mirror;
32+
import org.spongepowered.api.util.rotation.Rotation;
3433
import org.spongepowered.api.world.BlockChangeFlags;
35-
import org.spongepowered.api.world.biome.Biome;
3634
import org.spongepowered.api.world.server.ServerWorld;
3735
import org.spongepowered.api.world.volume.archetype.block.entity.BlockEntityArchetypeVolume;
3836
import org.spongepowered.api.world.volume.archetype.entity.EntityArchetypeVolume;

src/main/java/org/spongepowered/api/world/volume/stream/VolumePositionTranslators.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
import org.spongepowered.api.util.rotation.Rotation;
3131
import org.spongepowered.api.world.volume.Volume;
3232
import org.spongepowered.math.imaginary.Quaterniond;
33+
import org.spongepowered.math.vector.Vector3d;
3334
import org.spongepowered.math.vector.Vector3i;
3435

3536
import java.util.Objects;
37+
import java.util.function.BiFunction;
3638
import java.util.function.Function;
3739

3840
public final class VolumePositionTranslators {
@@ -41,28 +43,31 @@ public static <W extends Volume, E> VolumePositionTranslator<W, E> identity() {
4143
return element -> element;
4244
}
4345

44-
public static <W extends Volume> VolumePositionTranslator<W, BlockState> rotateBlocksOn(final Vector3i center, final Rotation rotation) {
45-
return VolumePositionTranslators.rotateOn(center, rotation, (state) -> state.rotate(rotation));
46+
public static <W extends Volume> VolumePositionTranslator<W, BlockState> rotateBlocksOn(final Vector3i start, final Vector3d center, final Rotation rotation) {
47+
return VolumePositionTranslators.rotateOn(start, center, rotation, (position, state) -> state.rotate(rotation));
4648
}
4749

48-
public static <W extends Volume> VolumePositionTranslator<W, Entity> rotateEntitiesOn(final Vector3i center, final Rotation rotation) {
49-
return VolumePositionTranslators.rotateOn(center, rotation, (entity) -> {
50-
entity.setRotation(entity.rotation().add(0, (float) rotation.angle() / 360, 0));
50+
public static <W extends Volume> VolumePositionTranslator<W, Entity> rotateEntitiesOn(final Vector3i start, final Vector3d center, final Rotation rotation) {
51+
return VolumePositionTranslators.rotateOn(start, center, rotation, (position, entity) -> {
52+
final Quaterniond q = Quaterniond.fromAngleDegAxis(rotation.angle().degrees(), 0, 1, 0);
53+
final Vector3d newPosition = q.rotate(entity.position().sub(center.toDouble())).add(center.toDouble());
54+
entity.setRotation(entity.rotation().add(0, (float) rotation.angle().degrees() / 360, 0));
55+
entity.setPosition(newPosition);
5156
return entity;
5257
});
5358
}
5459

55-
public static <W extends Volume> VolumePositionTranslator<W, BlockEntity> rotateBlockEntitiesOn(final Vector3i center,
60+
public static <W extends Volume> VolumePositionTranslator<W, BlockEntity> rotateBlockEntitiesOn(final Vector3i start, final Vector3i center,
5661
final Rotation rotation
5762
) {
58-
return VolumePositionTranslators.rotateOn(center, rotation, blockEntity -> blockEntity.rotate(rotation));
63+
return VolumePositionTranslators.rotateOn(start, center.toDouble(), rotation, (position, blockEntity) -> blockEntity.rotate(rotation));
5964
}
6065

61-
public static <W extends Volume, E> VolumePositionTranslator<W, E> rotateOn(final Vector3i center, final Rotation rotation,
62-
final Function<E, E> elementRotation
66+
public static <W extends Volume, E> VolumePositionTranslator<W, E> rotateOn(final Vector3i start, final Vector3d center, final Rotation rotation,
67+
final BiFunction<Vector3i, E, E> elementRotation
6368
) {
6469
return element -> {
65-
final Quaterniond q = Quaterniond.fromAngleDegAxis(rotation.angle(), 0, 1, 0);
70+
final Quaterniond q = Quaterniond.fromAngleDegAxis(rotation.angle().degrees(), 0, 1, 0);
6671
final Vector3i v = q.rotate(element.position().sub(center).toDouble()).toInt().add(center);
6772
return VolumeElement.of(element.volume(), elementRotation.apply(element.type()), v);
6873
};

0 commit comments

Comments
 (0)