Fixed problems with sorting collinear and intersecting edges caused by chain resolution in partition monotone

This commit is contained in:
2025-05-21 21:27:37 -04:00
parent c101c2e1dd
commit 3426829c2b
2 changed files with 80 additions and 34 deletions

View File

@@ -72,7 +72,8 @@ import com.aaaaahhhhhhh.bananapuncher714.mesh.region.RegionRule;
*/
public class Mesh< T extends Region > {
public static final double VERTEX_TOLERANCE = 1e-7;
public static final double ANGLE_TOLERANCE = Math.sin( Math.toRadians( 1e-10 ) );
public static final double ANGLE_TOLERANCE = Math.toRadians( 1e-10 );
public static final double CROSS_TOLERANCE = Math.sin( ANGLE_TOLERANCE );
// All points in the graph
protected Collection< Vertex > vertices = new ArrayDeque< Vertex >();
@@ -512,7 +513,7 @@ public class Mesh< T extends Region > {
final double angle = r.cross( s );
// Ignore edges that are not collinear
if ( Math.abs( angle ) <= ANGLE_TOLERANCE ) {
if ( Math.abs( angle ) <= CROSS_TOLERANCE ) {
// Compare which edge is shorter
if ( r.lengthSquared() < s.lengthSquared() ) {
@@ -829,7 +830,7 @@ public class Mesh< T extends Region > {
}
// Fast forward to the start of a potential collinear chain, since this edge may be in the middle of one
while ( Math.abs( edge.toVector2d().normalize().cross( edge.getPrev().toVector2d().normalize() ) ) <= ANGLE_TOLERANCE ) {
while ( Math.abs( edge.toVector2d().normalize().cross( edge.getPrev().toVector2d().normalize() ) ) <= CROSS_TOLERANCE ) {
edge = edge.getNext();
}
@@ -839,7 +840,7 @@ public class Mesh< T extends Region > {
final Vector2d a = edge.toVector2d().normalize();
final Vector2d b = next.toVector2d().normalize();
if ( Math.abs( a.cross( b ) ) <= ANGLE_TOLERANCE ) {
if ( Math.abs( a.cross( b ) ) <= CROSS_TOLERANCE ) {
// We can more or less unlink edges for free at this point
// since we can guarantee each edge borders one exterior
// and one interior region, and no two regions share an edge.
@@ -1160,12 +1161,11 @@ public class Mesh< T extends Region > {
// Get the cross value for this vertex to the current event vertex
final Vector2d toEvent = event.getPosition().subtracted( vert.getPosition() ).normalize();
final double upperCross = clamp( CROSS.cross( toEvent ), -1, 1 );
final double upperAngle = Math.asin( upperCross );
// Check over each visibility region and update the upper cross value
for ( final Iterator< VisibilityRegion > regionIt = regions.iterator(); regionIt.hasNext(); ) {
final VisibilityRegion region = regionIt.next();
if ( region.upper != MAX_CROSS && Math.abs( upperAngle - Math.asin( region.upper ) ) < ANGLE_TOLERANCE ) {
if ( region.upper != MAX_CROSS && Math.abs( upperCross - region.upper ) < CROSS_TOLERANCE ) {
// Make sure the region upper value has been initialized, before checking
// if this vertex is collinear with the previous vertex
@@ -1194,9 +1194,9 @@ public class Mesh< T extends Region > {
// Get the angle difference between the region's upper and lower bounds
// but set it to -1 if it the lower region has not been initialized
final double angleDifference = region.lower == MIN_CROSS ? -1 : ( Math.asin( region.lower ) - upperAngle );
final double crossDifference = region.lower == MIN_CROSS ? -1 : ( region.lower - upperCross );
if ( Math.abs( angleDifference ) <= ANGLE_TOLERANCE ) {
if ( Math.abs( crossDifference ) <= CROSS_TOLERANCE ) {
// The event vertex is not collinear with the previous upper
// vertex, but it _is_ collinear with the previous lower vertex!
@@ -1234,7 +1234,7 @@ public class Mesh< T extends Region > {
// bounds have already converged, and met at this collinear
// vertex.
regionIt.remove();
} else if ( angleDifference > ANGLE_TOLERANCE ) {
} else if ( crossDifference > CROSS_TOLERANCE ) {
// If the upper angle is less than the lower angle, then we know
// that the region is no longer visible to this vertex
regionIt.remove();
@@ -1291,12 +1291,11 @@ public class Mesh< T extends Region > {
// Get the cross value for this vertex to the current event vertex
final Vector2d toEvent = event.getPosition().subtracted( vert.getPosition() ).normalize();
final double lowerCross = clamp( CROSS.cross( toEvent ), -1, 1 );
final double lowerAngle = Math.asin( lowerCross );
// Check over each visibility region and update the upper cross value
for ( final Iterator< VisibilityRegion > regionIt = regions.iterator(); regionIt.hasNext(); ) {
final VisibilityRegion region = regionIt.next();
if ( region.lower != MAX_CROSS && Math.abs( lowerAngle - Math.asin( region.lower ) ) < ANGLE_TOLERANCE ) {
if ( region.lower != MAX_CROSS && Math.abs( lowerCross - region.lower ) < CROSS_TOLERANCE ) {
// Make sure the region lower value has been initialized, before checking
// if this vertex is collinear with the previous vertex
@@ -1324,9 +1323,9 @@ public class Mesh< T extends Region > {
// Get the angle difference between the region's upper and lower bounds
// but set it to -1 if it the upper region has not been initialized
final double angleDifference = region.upper == MAX_CROSS ? -1 : ( lowerAngle - Math.asin( region.upper ) );
final double crossDifference = region.upper == MAX_CROSS ? -1 : ( lowerCross -region.upper );
if ( Math.abs( angleDifference ) <= ANGLE_TOLERANCE ) {
if ( Math.abs( crossDifference ) <= CROSS_TOLERANCE ) {
// The event vertex is not collinear with the previous upper
// vertex, but it _is_ collinear with the previous upper vertex!
@@ -1363,7 +1362,7 @@ public class Mesh< T extends Region > {
// bounds have already converged, and met at this collinear
// vertex.
regionIt.remove();
} else if ( angleDifference > ANGLE_TOLERANCE ) {
} else if ( crossDifference > CROSS_TOLERANCE ) {
// If the upper angle is less than the lower angle, then we know
// that the region is no longer visible to this vertex
regionIt.remove();
@@ -1961,7 +1960,6 @@ public class Mesh< T extends Region > {
// Get the direction of this chain
final Vector2d chainDirection = chain.getDest().getPosition().subtracted( chain.getOrigin().getPosition() );
System.out.println( chain + ":\t" + chain.links.get( 0 ) + "\t to \t" + chain.links.get( 1 ) + "\t to \t" + chain.links.get( 2 ) );
System.out.println( "Linking chain" );
// Setup the left and right edges if the first link is not a direct edge from the origin to the midpoint
if ( chain.links.get( 0 ).getDest() != chain.getMidpoint() ) {
@@ -1984,8 +1982,7 @@ public class Mesh< T extends Region > {
System.out.println( "Starting chain " + chain.getOrigin() );
Chain initial = chain;
Chain previousChain;
do {
selectedChains.remove( chain );
@@ -2177,7 +2174,7 @@ public class Mesh< T extends Region > {
// selectedChains.remove( chain.next );
// cs.remove( chain.next );
// break;
} while ( ( chain = chain.next ) != null );
} while ( ( chain = chain.next ) != null && selectedChains.contains( chain ) );
// TODO Make sure the edges are fully attached/detached! Dangling edges are detected!
@@ -2232,6 +2229,22 @@ public class Mesh< T extends Region > {
// System.out.println( "-1 \t" + previousChain.getMidpoint() );
}
System.out.println( "Start:" );
for ( HalfEdge e : initial.getOrigin() ) {
System.out.println( e );
}
do {
System.out.println( "Mid:" );
for ( HalfEdge e : initial.getMidpoint() ) {
System.out.println( e );
}
} while ( previousChain != initial && ( initial = initial.next ) != null );
System.out.println( "End:" );
for ( HalfEdge e : previousChain.getDest() ) {
System.out.println( e );
}
// System.out.println( "Origin: " + previousChain.getOrigin() );
// for ( HalfEdge e : previousChain.getOrigin() ) {
// System.out.println( e + "\t" + e.toVector2d() );
@@ -2413,21 +2426,34 @@ public class Mesh< T extends Region > {
// a1 < a2
final Vector2d a1 = a.getOrigin().getPosition();
final Vector2d a2 = a.getDest().getPosition();
final Vector2d aLine = a.toVector2d().normalize();
// b1 < b2
final Vector2d b1 = b.getOrigin().getPosition();
final Vector2d b2 = b.getDest().getPosition();
final Vector2d bLine = b.toVector2d().normalize();
final int compared = compare( a.getOrigin(), b.getOrigin() );
double cross;
if ( compared == 0 ) {
cross = b2.subtracted( b1 ).normalized().cross( a2.subtracted( a1 ).normalized() );
cross = bLine.cross( aLine );
} else if ( compared < 0 ) {
cross = b1.subtracted( a1 ).normalized().cross( a2.subtracted( a1 ).normalized() );
// If cross is still 0, compare the other
cross = b1.subtracted( a1 ).normalized().cross( aLine );
if ( Math.abs( cross ) < CROSS_TOLERANCE ) {
cross = b2.subtracted( a1 ).normalized().cross( aLine );
}
} else {
cross = b2.subtracted( b1 ).normalized().cross( a1.subtracted( b1 ).normalized() );
// If cross is still 0, compare the other
cross = bLine.cross( a1.subtracted( b1 ).normalized() );
if ( Math.abs( cross ) < CROSS_TOLERANCE ) {
cross = bLine.cross( a2.subtracted( b1 ).normalize() );
}
}
if ( Math.asin( Math.min( 1, Math.abs( cross ) ) ) > ANGLE_TOLERANCE ) {
// System.out.println( a + " vs " + b + " is " + cross );
if ( Math.abs( cross ) > CROSS_TOLERANCE ) {
return cross > 0;
} else {
// Collinear
@@ -2452,6 +2478,7 @@ public class Mesh< T extends Region > {
rightGoing.add( edge );
} else {
leftGoing.add( edge );
// System.out.println( "Removing " + edge.getSym() );
if ( !edgeCollection.remove( edge.getSym() ) ) {
throw new IllegalStateException( "Edge not added to the edge collection!" );
}
@@ -2494,6 +2521,13 @@ public class Mesh< T extends Region > {
}
throw new IllegalStateException( "Lower does not have an upper edge!" );
} if ( !interior.contains( upper.getSym() ) ) {
System.out.println( "Current: " + event );
System.out.println( "Lower: " + lower );
System.out.println( "Upper: " + upper );
System.out.println( "Edges:" );
for ( final HalfEdge e : edgeCollection ) {
System.out.println( e + "\t" + interior.contains( e ) + "\t" + interior.contains( e.getSym() ) );
}
throw new IllegalStateException( "Polygon is not simple!" );
} else if ( upper.getOrigin() == event || lower.getOrigin() == event ) {
throw new IllegalStateException( "Vertex is invalid!" );
@@ -2644,6 +2678,7 @@ public class Mesh< T extends Region > {
// now that we have finally finished adding new edges.
for ( final HalfEdge edge : rightGoing ) {
if ( isPositive( edge ) ) {
// System.out.println( "Adding " + edge );
edgeCollection.insert( edge );
} else {
throw new IllegalStateException( "Edge suddenly changed sign!" );

View File

@@ -95,13 +95,13 @@ public class MeshingTest2 extends JPanel {
// draw = planes.get( new Random().nextInt( planes.size() ) );
System.out.println( "Draw is " + draw );
// Attempt to mesh all planes
// try {
// test( planes );
// } catch ( PolygonException e ) {
// draw = e.getPlane();
// System.out.println( "Draw is now " + draw );
// }
// Attempt to mesh all planes
try {
test( planes );
} catch ( PolygonException e ) {
draw = e.getPlane();
System.out.println( "Draw is now " + draw );
}
final Collection< Vertex > data = process( draw );
final Collection< EdgePolygon > polys = triangulate( draw );
@@ -265,8 +265,18 @@ public class MeshingTest2 extends JPanel {
// Make sure this works
mesh = mesh.copyOf();
final Collection< EdgePolygon > polys = mesh.mesh( false );
Collection< EdgePolygon > polys;
try {
polys = mesh.mesh( false );
chains = mesh.chains;
} catch ( IllegalStateException e ) {
e.printStackTrace();
polys = mesh.mesh( true );
chains = mesh.chains;
}
long end = System.currentTimeMillis();
System.out.println( "Took " + ( end - start ) + "ms" );
@@ -646,6 +656,7 @@ public class MeshingTest2 extends JPanel {
int count = 2;
Random random = new Random( hashCode() );
final int spacing = 25;
for ( final EdgePolygon p : polygons ) {
final Collection< HalfEdge > edges = p.getEdges();
@@ -655,9 +666,9 @@ public class MeshingTest2 extends JPanel {
Point p1 = edge.getOrigin().getPosition();
Point p2 = edge.getDest().getPosition();
g.drawLine(
( int ) ( ( centerX + p1.getX() + count * 25 ) * scale ) + offsetX,
( int ) ( ( centerX + p1.getX() + count * spacing ) * scale ) + offsetX,
( int ) ( ( centerY - p1.getY() - 150 ) * scale ) + offsetY,
( int ) ( ( centerX + p2.getX() + count * 25 ) * scale ) + offsetX,
( int ) ( ( centerX + p2.getX() + count * spacing ) * scale ) + offsetX,
( int ) ( ( centerY - p2.getY() - 150 ) * scale ) + offsetY
);
@@ -670,7 +681,7 @@ public class MeshingTest2 extends JPanel {
final double diff = scale * 0.15;
if ( !verts.add( edge.getOrigin() ) ) {
g.drawRect( ( int ) ( ( centerX + p1.getX() + count * 25 ) * scale ) - ( int ) diff + offsetX, ( int ) ( ( centerY - p1.getY() - 150 ) * scale ) - ( int ) diff + offsetY, ( int ) ( diff * 2 ), ( int ) ( diff * 2 ) );
g.drawRect( ( int ) ( ( centerX + p1.getX() + count * spacing ) * scale ) - ( int ) diff + offsetX, ( int ) ( ( centerY - p1.getY() - 150 ) * scale ) - ( int ) diff + offsetY, ( int ) ( diff * 2 ), ( int ) ( diff * 2 ) );
}
}
count++;