Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add custom plane splitvoxels #46

Merged
merged 30 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9502d5c
changed docstrung for getDirection to specify that it gets direction …
Jannetty Oct 2, 2024
baeff5a
adding initial Plane, Point, Vector classes and associated tests
Jannetty Oct 2, 2024
4439952
adding last file
Jannetty Oct 2, 2024
8009e39
adding Plane container and Plane factory to make planes from potts enums
Jannetty Oct 2, 2024
114f69d
wip many tests failing, fixing PottsLocationTest.java
Jannetty Oct 2, 2024
bcde1bd
corrected normal vectors in PottsPlaneFactory. Updated tests. Added t…
Jannetty Oct 4, 2024
ab94aa6
formatting fixes
Jannetty Oct 4, 2024
3bdd127
formatting fixes. Added private constructor to PottsPlaneFactory
Jannetty Oct 4, 2024
78425a6
formatting fixes
Jannetty Oct 4, 2024
4c97365
moved all points and vectors to int3Ds, expanded direction enum, remo…
Jannetty Oct 4, 2024
f1208b9
small changes to PottsEnums test, formatting fixes
Jannetty Oct 4, 2024
e61a6f1
hopefully fixed import orders
Jannetty Oct 4, 2024
3207aab
small fixes
Jannetty Oct 4, 2024
70fdf74
removed extra split function
Jannetty Oct 4, 2024
67b2122
formatting fixes
Jannetty Oct 4, 2024
00e33d8
Divide Distance to Plane by Normal Vector Magnitude (#52)
daniellevahdat Oct 9, 2024
21b7089
moved Plane to Potts, changed point type to Voxel, removed unused fun…
Jannetty Oct 10, 2024
8430c29
change plane to have point represented as voxel instead of int3d
Jannetty Oct 10, 2024
6e89218
changed signedDistance function to take voxel
Jannetty Oct 10, 2024
a095a9f
updated test
Jannetty Oct 10, 2024
25f5aa4
changed enum back, formatting fixes
Jannetty Oct 10, 2024
e8abcdf
removing test.cass
Jannetty Oct 10, 2024
e4227fd
formatting fixes
Jannetty Oct 10, 2024
87bb950
formatting fix
Jannetty Oct 10, 2024
2af086c
Update src/arcade/potts/env/location/PottsLocation.java
Jannetty Oct 11, 2024
157ea45
addressing Jess's comments. Normalizing plane normal vector.
Jannetty Oct 11, 2024
c728a39
formatting fixes
Jannetty Oct 11, 2024
af59ba9
added a few white spaces
Jannetty Oct 11, 2024
ee9897c
Update src/arcade/potts/env/location/PottsLocation.java
Jannetty Oct 11, 2024
e9bdd34
Update test/arcade/potts/env/location/PottsLocationTest.java
Jannetty Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions src/arcade/potts/env/location/Plane.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package arcade.potts.env.location;

import sim.util.Double3D;
import sim.util.Int3D;
import arcade.potts.util.PottsEnums.Direction;

/**
* A plane in 3D space.
*/

public final class Plane {
/** A point on the plane. */
public final Voxel referencePoint;

/** The unit normal vector to the plane. */
public final Double3D unitNormalVector;

/**
* Creates a plane from a point and a vector.
*
* @param voxel a point on the plane
* @param normalVector the normal vector to the plane
*/
public Plane(Voxel voxel, Int3D normalVector) {
this.referencePoint = voxel;
this.unitNormalVector = scaleNormalVector(normalVector);
}

/**
* Creates a plane from a point and a direction.
*
* @param voxel a point on the plane
* @param direction the direction of the plane
*/
public Plane(Voxel voxel, Direction direction) {
this(voxel, direction.vector);
}

/**
* Determines the magnitude of the normal vector.
*
* @param normalVector the normal vector
* @return the magnitude of the normal vector
*/
static double getNormalVectorMagnitude(Int3D normalVector) {
return Math.sqrt(normalVector.getX() * normalVector.getX()
+ normalVector.getY() * normalVector.getY()
+ normalVector.getZ() * normalVector.getZ());
}

/**
* Scales the normal vector to a unit vector.
*
* @param normalVector the normal vector
* @return the unit normal vector
*/
static Double3D scaleNormalVector(Int3D normalVector) {
double magnitude = getNormalVectorMagnitude(normalVector);
double scaledX = normalVector.getX() / magnitude;
double scaledY = normalVector.getY() / magnitude;
double scaledZ = normalVector.getZ() / magnitude;
Double3D unitNormalVector = new Double3D(scaledX, scaledY, scaledZ);
return unitNormalVector;
}

/**
* Determines distance from a point to the plane.
*
* The distance is positive if the point is on the same side of the plane
* as the normal vector and negative if it is on the opposite side.
*
* @param point the point
* @return the distance from the point to the plane.
*
*/
public double signedDistanceToPlane(Voxel point) {
double dotProduct = (point.x - referencePoint.x) * unitNormalVector.getX()
+ (point.y - referencePoint.y) * unitNormalVector.getY()
+ (point.z - referencePoint.z) * unitNormalVector.getZ();
return dotProduct;
}

/**
* Determines if two planes are equal.
*
* @param obj the plane to compare
* @return {@code true} if the planes are equal, {@code false} otherwise
*/
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Plane other = (Plane) obj;
return referencePoint.equals(other.referencePoint)
&& unitNormalVector.equals(other.unitNormalVector);
}

/**
* Returns a hash code for the plane.
*
* @return a hash code for the plane
*/
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + referencePoint.hashCode();
hash = 31 * hash + Double.hashCode(unitNormalVector.getX());
hash = 31 * hash + Double.hashCode(unitNormalVector.getY());
hash = 31 * hash + Double.hashCode(unitNormalVector.getZ());
return hash;
}
}
208 changes: 50 additions & 158 deletions src/arcade/potts/env/location/PottsLocation.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ public void update(int id, int[][][] ids, int[][][] regions) {
* @return a location with the split voxels
*/
public Location split(MersenneTwisterFast random) {
return split(random, null, null, DEFAULT_SPLIT_SELECTION_PROBABILITY);
Plane divisionPlane = new Plane(getCenter(), getDirection(random));
return split(random, divisionPlane, DEFAULT_SPLIT_SELECTION_PROBABILITY);
}

/**
Expand All @@ -287,11 +288,13 @@ public Location split(MersenneTwisterFast random) {
* @return a location with the split voxels
*/
public Location split(MersenneTwisterFast random, ArrayList<Integer> offsets) {
return split(random, offsets, null, DEFAULT_SPLIT_SELECTION_PROBABILITY);
Plane divisionPlane = new Plane(getOffset(offsets), getDirection(random));
return split(random, divisionPlane, DEFAULT_SPLIT_SELECTION_PROBABILITY);
}

/**
* Splits location voxels into two lists with given offset and direction.
* Splits location voxels into two lists with given offset, direction,
* and probability.
* <p>
* The location is split at the point specified by offsets along the given
* direction. The lists of locations are guaranteed to be connected. One of
Expand All @@ -301,49 +304,44 @@ public Location split(MersenneTwisterFast random, ArrayList<Integer> offsets) {
* @param random the seeded random number generator
* @param offsets the percentage offset in each direction for split point
* @param direction the direction of the split
* @param probability the probability to decide which split to return
* @return a location with the split voxels
*/
public Location split(MersenneTwisterFast random, ArrayList<Integer> offsets,
Direction direction) {
return split(random, offsets, direction, DEFAULT_SPLIT_SELECTION_PROBABILITY);
Direction direction, Double probability) {
Plane divisionPlane = new Plane(getOffset(offsets), direction.vector);
Jannetty marked this conversation as resolved.
Show resolved Hide resolved
return split(random, divisionPlane, probability);
}

/**
* Splits location voxels into two lists.
* <p>
* The location is split at the point specified by offsets along the given
* direction. One of the splits is assigned to the current location and the
* other is returned with the given probability.
* The location is split along the provided plane. One of the splits is
* assigned to the current location and the other is returned with the
* given probability.
* <p>
* If offsets not are provided, the resulting lists are guaranteed to be
* connected, and generally will be balanced in size. If offsets is
* provided, the resulting lists are guaranteed to be connected but will not
* necessarily be balanced in size.
* If the plane of division is through the center of the location, the
* resulting lists are guaranteed to be connected, and generally will be
* balanced in size. If the plane of division is not through the center
* of the location, the resulting lists are guaranteed to be connected
* but will not necessarily be balanced in size.
*
* @param random the seeded random number generator
* @param offsets the percentage offset in each direction for split point
* @param direction the direction of the split
* @param plane the plane of the split
* @param probability the probability to decide which split to return
* @return a location with the split voxels
*/
public Location split(MersenneTwisterFast random, ArrayList<Integer> offsets,
Direction direction, Double probability) {
public Location split(MersenneTwisterFast random,
Plane plane, Double probability) {
// Initialize lists of split voxels
ArrayList<Voxel> voxelsA = new ArrayList<>();
ArrayList<Voxel> voxelsB = new ArrayList<>();

// Calculate split point.
Voxel splitpoint = offsets == null ? getCenter() : getOffset(offsets);

// Perform the split along the specified direction
if (direction == null) {
direction = getDirection(random);
}

splitVoxels(direction, voxels, voxelsA, voxelsB, splitpoint, random);
splitVoxels(plane, voxels, voxelsA, voxelsB, random);
connectVoxels(voxelsA, voxelsB, this, random);

if (offsets == null) {

Voxel locCenter = getCenter();
if (plane.referencePoint.equals(locCenter)) {
balanceVoxels(voxelsA, voxelsB, this, random);
}

Expand Down Expand Up @@ -569,7 +567,8 @@ void updateCenter(int x, int y, int z, int change) {
abstract ArrayList<Voxel> getSelected(Voxel focus, double n);

/**
* Gets the direction of the slice.
* Gets the direction of the slice orthagonal to the direction with
* the smallest diameter.
*
* @param random the seeded random number generator
* @return the direction of the slice
Expand Down Expand Up @@ -627,141 +626,34 @@ Location separateVoxels(ArrayList<Voxel> voxelsA, ArrayList<Voxel> voxelsB,
calculateCenter();
return makeLocation(voxelsB);
}

/**
* Splits the voxels in the location along a given direction.
* Splits the voxels in the location into two lists along a given plane.
* <p>
* The voxels are split into two lists based on their position relative to
* the plane. Voxels on the plane are randomly assigned to one of the lists.
*
* @param direction the direction of the slice
* @param voxels the list of voxels
* @param voxelsA the container list for the first half of the split
* @param voxelsB the container list for the second half of the split
* @param center the center voxel
* @param random the seeded random number generator
* @param plane the plane to split the voxels along
Jannetty marked this conversation as resolved.
Show resolved Hide resolved
* @param voxels the list of voxels to split
* @param voxelsA list of voxels on side of plane the opposite the normal
* @param voxelsB list of voxels on side of plane the same as the normal
* @param random the seeded random number generator
*/
static void splitVoxels(Direction direction, ArrayList<Voxel> voxels,
static void splitVoxels(Plane plane, ArrayList<Voxel> voxels,
ArrayList<Voxel> voxelsA, ArrayList<Voxel> voxelsB,
Voxel center, MersenneTwisterFast random) {
MersenneTwisterFast random) {
for (Voxel voxel : voxels) {
switch (direction) {
case ZX_PLANE:
if (voxel.y < center.y) {
voxelsA.add(voxel);
} else if (voxel.y > center.y) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case YZ_PLANE:
if (voxel.x < center.x) {
voxelsA.add(voxel);
} else if (voxel.x > center.x) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case XY_PLANE:
if (voxel.z < center.z) {
voxelsA.add(voxel);
} else if (voxel.z > center.z) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case NEGATIVE_XY:
if (voxel.x - center.x > center.y - voxel.y) {
voxelsA.add(voxel);
} else if (voxel.x - center.x < center.y - voxel.y) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case POSITIVE_XY:
if (voxel.x - center.x > voxel.y - center.y) {
voxelsA.add(voxel);
} else if (voxel.x - center.x < voxel.y - center.y) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case NEGATIVE_YZ:
if (voxel.y - center.y > center.z - voxel.z) {
voxelsA.add(voxel);
} else if (voxel.y - center.y < center.z - voxel.z) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case POSITIVE_YZ:
if (voxel.y - center.y > voxel.z - center.z) {
voxelsA.add(voxel);
} else if (voxel.y - center.y < voxel.z - center.z) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case NEGATIVE_ZX:
if (voxel.z - center.z > center.x - voxel.x) {
voxelsA.add(voxel);
} else if (voxel.z - center.z < center.x - voxel.x) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
case POSITIVE_ZX:
if (voxel.z - center.z > voxel.x - center.x) {
voxelsA.add(voxel);
} else if (voxel.z - center.z < voxel.x - center.x) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
break;
default:
break;
double distance = plane.signedDistanceToPlane(voxel);
if (distance < 0) {
voxelsA.add(voxel);
} else if (distance > 0) {
voxelsB.add(voxel);
} else {
if (random.nextDouble() > 0.5) {
voxelsA.add(voxel);
} else {
voxelsB.add(voxel);
}
}
}
}
Expand Down
Loading
Loading