Introduce fuzzy iterating when finding chains; Found another bug when detecting chain collisions

This commit is contained in:
2025-05-23 02:17:25 -04:00
parent 29a0c04fae
commit 586fb04c02
3 changed files with 598 additions and 101 deletions

View File

@@ -231,6 +231,25 @@ public class Mesh< T extends Region > {
return copy;
}
/**
*
*
* @return A collection of triangles
*/
public Collection< Polygon > meshify() {
switch ( state ) {
case DIRTY:
simplify();
case SIMPLIFIED:
generateRegions();
case TRIANGULATION_READY:
return mesh();
default:
throw new IllegalStateException( "Invalid mesh state!" );
}
}
/**
* Do a check over all vertices to see if there are any within
* VERTEX_TOLERANCE of each other. If so, then merge them.
@@ -973,13 +992,13 @@ public class Mesh< T extends Region > {
}
// Have a single set of edges
final TreeSet< Vertex > vertices = new TreeSet< Vertex >( Mesh::compare );
vertices.addAll( newVertices.values() );
final TreeSet< Vertex > fuzzyVertices = new TreeSet< Vertex >( Mesh::fuzzyCompare );
fuzzyVertices.addAll( newVertices.values() );
// Sort each vertex so that the edge they are pointing to is the least edge
vertices.parallelStream().forEach( v -> sort( v ) );
fuzzyVertices.parallelStream().forEach( v -> sort( v ) );
final Collection< Link > allChains = findChains( vertices, edges );
final Collection< Link > allChains = findChains( fuzzyVertices, edges );
final Collection< Link > chains = maximizeChains( allChains );
if ( !handlers.isEmpty() ) {
final Collection< Chain > newChains = new HashSet< Chain >();
@@ -1034,10 +1053,15 @@ public class Mesh< T extends Region > {
mergeChains( chains, edges );
return partitionMonotone( vertices, edges ).parallelStream()
.map( Mesh::triangulate )
.flatMap( p -> p.parallelStream() )
.collect( Collectors.toSet() );
// return Collections.emptySet();
final TreeSet< Vertex > vertices = new TreeSet< Vertex >( Mesh::compare );
vertices.addAll( fuzzyVertices );
return Collections.emptySet();
// return partitionMonotone( vertices, edges ).parallelStream()
// .map( Mesh::triangulate )
// .flatMap( p -> p.parallelStream() )
// .collect( Collectors.toSet() );
}
/*
@@ -1431,6 +1455,10 @@ public class Mesh< T extends Region > {
// The new chain is a continuation of this chain
other.next = chain;
chain.previous = other;
} else if ( chainMidpoint == other.getOrigin() && chainDestination == other.getMidpoint() ) {
System.out.println( "BUG" );
other.previous = chain;
chain.next = other;
} else if ( compare( other.getDest(), chainOrigin ) > 0 ) {
// Do the chains even overlap?
if ( chainOrigin == other.getMidpoint() ) {
@@ -1457,6 +1485,31 @@ public class Mesh< T extends Region > {
intersects = otherDirection.cross( secondLink.toVector2d() ) < 0 ^ cross < 0;
}
if ( intersects ) {
synchronized ( intersections ) {
intersections.add( other );
}
other.intersections.add( chain );
}
} else if ( chainDestination == other.getMidpoint() ) {
System.out.println( "BUG 2" );
final Vector2d otherDirection = other.getDest().getPosition().subtracted( other.getOrigin().getPosition() );
final double cross = r.cross( otherDirection );
boolean intersects = true;
final HalfEdge firstLink = other.links.get( 0 );
final HalfEdge secondLink = other.links.get( 1 );
if ( firstLink.getDest() == other.getMidpoint() ) {
// Is the first link a direct connection?
intersects = interior.contains( firstLink ) ^ cross < 0;
} else if ( secondLink.getDest() == other.getDest() ) {
// Is the second link a direct connection?
intersects = interior.contains( secondLink ) ^ cross < 0;
} else {
// The chain is comprised of only vertices...
intersects = otherDirection.cross( secondLink.toVector2d() ) < 0 ^ cross < 0;
}
if ( intersects ) {
synchronized ( intersections ) {
intersections.add( other );
@@ -1478,6 +1531,27 @@ public class Mesh< T extends Region > {
intersects = r.cross( secondEdgeVec ) < 0 ^ cross < 0;
}
if ( intersects ) {
synchronized ( intersections ) {
intersections.add( other );
}
other.intersections.add( chain );
}
} else if ( other.getOrigin() == chainMidpoint ) {
// Third and last case
// destination. We need to check for that case too.
final Vector2d otherDirection = other.getDest().getPosition().subtracted( other.getOrigin().getPosition() ).normalize();
final double cross = r.cross( otherDirection );
boolean intersects = true;
if ( firstEdge.getDest() == chainMidpoint ) {
intersects = interior.contains( firstEdge ) ^ cross < 0;
} else if ( secondEdge.getDest() == chainDestination ) {
intersects = interior.contains( secondEdge ) ^ cross < 0;
} else {
intersects = r.cross( secondEdgeVec ) < 0 ^ cross < 0;
}
if ( intersects ) {
synchronized ( intersections ) {
intersections.add( other );
@@ -1808,8 +1882,6 @@ public class Mesh< T extends Region > {
throw new IllegalStateException( "Lower partition not found!" );
}
top.chains.addAll( bottom.chains );
lowerEdgeMap.remove( bottom.upper );
// Merge the top and bottom partition
@@ -1821,7 +1893,13 @@ public class Mesh< T extends Region > {
// Update all visibility regions for the top and bottom partitions, separately
top.incrementLower( topLeft );
bottom.incrementUpper( bottomLeft );
// Problem... need to make bottom chains and top chains the same because merging regions must use the same chain map...
// TODO Do it... make a reverse region map for each chain... it only makes some sense...
// And then technically just combine all chain maps at the end because that also only makes sense
// Fixes the issues...
top.chains.addAll( bottom.chains );
// Merge the two partitions
top.add( bottom );
@@ -2342,6 +2420,7 @@ public class Mesh< T extends Region > {
if ( upper == null ) {
throw new IllegalStateException( "Lower does not have an upper edge!" );
} if ( !interior.contains( upper.getSym() ) ) {
System.out.println( upper );
throw new IllegalStateException( "Polygon is not simple!" );
} else if ( upper.getOrigin() == event || lower.getOrigin() == event ) {
throw new IllegalStateException( "Vertex is invalid!" );
@@ -2641,8 +2720,11 @@ public class Mesh< T extends Region > {
// Lazy solution, just sort the vertices
// Eventually we will remove this
// TODO Remove this NOW
toSort.parallelStream().forEach( v -> sort( v ) );
Map< Vertex, Point > pointMap = polygon.vertices.parallelStream().collect( Collectors.toMap( Function.identity(), v -> { return new Point( v.getPosition() ); } ) );
final Collection< Polygon > polygons = new ArrayDeque< Polygon >();
final Set< HalfEdge > scanned = new HashSet< HalfEdge >();
for ( final HalfEdge edge : polygon.getEdges() ) {
@@ -2651,7 +2733,7 @@ public class Mesh< T extends Region > {
final List< Point > points = new ArrayList< Point >();
do {
points.add( new Point( temp.getOrigin().getPosition() ) );
points.add( pointMap.get( temp.getOrigin() ) );
} while ( scanned.add( temp = temp.getNext() ) );
if ( points.size() != 3 ) {
@@ -2701,10 +2783,32 @@ public class Mesh< T extends Region > {
* @param edge
* @return
*/
public static boolean isPositive( HalfEdge edge ) {
private static boolean isPositive( HalfEdge edge ) {
return compare( edge.getOrigin(), edge.getDest() ) <= 0;
}
/*
* Since sometimes vertices will be off by a few floating point errors,
* it will cause problems because we have checks for tolerance, but if
* the sorting for vertices does not, it causes issues.
*/
private static int fuzzyCompare( final Vertex a, final Vertex b ) {
if ( a == b ) {
return 0;
}
final Vector2d aPos = a.getPosition();
final Vector2d bPos = b.getPosition();
final double xDiff = aPos.getX() - bPos.getX();
if ( Math.abs( xDiff ) < VERTEX_TOLERANCE ) {
return Double.compare( aPos.getY(), bPos.getY() );
} else {
return Double.compare( aPos.getX(), bPos.getX() );
}
}
private static int compare( final Vertex a, final Vertex b ) {
if ( a == b ) {
return 0;