Fixed problems with sorting collinear and intersecting edges caused by chain resolution in partition monotone
This commit is contained in:
@@ -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!" );
|
||||
|
||||
@@ -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 );
|
||||
chains = mesh.chains;
|
||||
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++;
|
||||
|
||||
Reference in New Issue
Block a user