diff --git a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java index 8dbc615..67838bb 100644 --- a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java +++ b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java @@ -983,6 +983,9 @@ public class Mesh< T extends Region > { // TODO Make not static public static class Chain { List< HalfEdge > links; + Set< Chain > intersections = new HashSet< Chain >(); + Chain previous; + Chain next; Chain( final Collection< HalfEdge > links ) { this.links = new ArrayList< HalfEdge >( links ); @@ -992,6 +995,10 @@ public class Mesh< T extends Region > { return links.get( 0 ).getOrigin(); } + public Vertex getMidpoint() { + return links.get( 1 ).getOrigin(); + } + public Vertex getDest() { return links.get( 2 ).getOrigin(); } @@ -1089,6 +1096,9 @@ public class Mesh< T extends Region > { // may be merged into a single partition, and each partition // may have a visibility region for the same vertex. Map< Vertex, Collection< VisibilityRegion > > regionMap = new HashMap< Vertex, Collection< VisibilityRegion > >(); + + // Keep track of all chains that were formed in this current partition. + // For all new chains, see what previous chains it may intersect with Collection< Chain > chains = new HashSet< Chain >(); Partition( final HalfEdge lower, final HalfEdge upper ) { @@ -1131,10 +1141,8 @@ public class Mesh< T extends Region > { // and we don't really care about what comes after links.add( edge ); - // TODO Check for intersections - final Chain chain = new Chain( links ); - chains.add( chain ); + addChain( chain ); } } else if ( upperCross < region.upper ) { @@ -1148,15 +1156,17 @@ public class Mesh< T extends Region > { // The event vertex is not collinear with the previous upper // vertex, but it _is_ collinear with the previous lower vertex! - // Remove the previous links - region.links.remove( region.upper ); + // Remove the previous links, but only if the upper is not exactly equal to the lower + if ( region.upper != region.lower ) { + region.links.remove( region.upper ); + region.upper = region.lower; + } // There should be exactly 1 link, the lower region's link if ( region.links.size() != 1 ) { throw new IllegalStateException( "Dangling link!" ); } - region.upper = region.lower; final List< HalfEdge > links = region.links.get( region.upper ); @@ -1172,10 +1182,8 @@ public class Mesh< T extends Region > { // and we don't really care about what comes after links.add( edge ); - // TODO Check for intersections - final Chain chain = new Chain( links ); - chains.add( chain ); + addChain( chain ); // Remove this vertex since we know the upper and lower // bounds have already converged, and met at this collinear @@ -1286,10 +1294,8 @@ public class Mesh< T extends Region > { // and we don't really care about what comes after links.add( edge ); - // TODO Check for intersections - final Chain chain = new Chain( links ); - chains.add( chain ); + addChain( chain ); } } else if ( lowerCross > region.lower ) { // Is the new cross value greater than the previous cross value? @@ -1302,16 +1308,17 @@ public class Mesh< T extends Region > { // The event vertex is not collinear with the previous upper // vertex, but it _is_ collinear with the previous upper vertex! - // Remove the previous links - region.links.remove( region.lower ); + // Remove the previous links, but only if the upper is not exactly equal to the lower + if ( region.upper != region.lower ) { + region.links.remove( region.lower ); + region.lower = region.upper; + } // There should be exactly 1 link, the lower region's link if ( region.links.size() != 1 ) { throw new IllegalStateException( "Dangling link!" ); } - region.lower = region.upper; - final List< HalfEdge > links = region.links.get( region.lower ); if ( links == null ) { @@ -1326,10 +1333,8 @@ public class Mesh< T extends Region > { // and we don't really care about what comes after links.add( edge ); - // TODO Check for intersections - final Chain chain = new Chain( links ); - chains.add( chain ); + addChain( chain ); // Remove this vertex since we know the upper and lower // bounds have already converged, and met at this collinear @@ -1384,6 +1389,58 @@ public class Mesh< T extends Region > { } } + /* + * Check all previous chains for intersections and stuff + */ + void addChain( final Chain chain ) { + final Vertex chainOrigin = chain.getOrigin(); + final Vertex chainMidpoint = chain.getMidpoint(); + final Vertex chainDestination = chain.getDest(); + + final Vector2d p = chainOrigin.getPosition(); + final Vector2d r = chainDestination.getPosition().subtracted( p ); + for ( final Chain other : chains ) { + // The new chain is a continuation of this chain + if ( other.getMidpoint() == chainOrigin && other.getDest() == chainMidpoint ) { + other.next = chain; + chain.previous = other; + } else if ( compare( other.getDest(), chainOrigin ) > 0 ) { + // Do the chains even overlap? + if ( other.getOrigin() != chainOrigin && other.getDest() != chainDestination ) { + // Make sure the chains don't share the same origin or destination + + // Perform a basic check + // Both edges may intersect somewhere in the middle + final Vector2d q = other.getOrigin().getPosition(); + final Vector2d s = other.getDest().getPosition().subtracted( q ); + + final Vector2d pq = q.subtracted( p ); + final double pqr = pq.cross( r ); + final double rs = r.cross( s ); + + // Check if parallel + if ( rs != 0 ) { + // Calculate t and u + final double t = pq.cross( s ) / rs; + final double u = pqr / rs; + + final double uTol = VERTEX_TOLERANCE / s.length(); + + // Do the line segments intersect + // Allow for overlap + if ( t >= 0 && t <= 1 && u > -uTol && u < ( 1 + uTol ) ) { + // The chains intersect! We don't care about where. + + chain.intersections.add( other ); + other.intersections.add( chain ); + } + } + } + } + } + chains.add( chain ); + } + void add( final Vertex vertex, final VisibilityRegion region ) { Collection< VisibilityRegion > regions; if ( regionMap.containsKey( vertex ) ) { @@ -1579,6 +1636,14 @@ public class Mesh< T extends Region > { if ( region.lower != MIN_CROSS ) { copyRegion.lower = region.lower; copyRegion.links.put( region.lower, region.links.remove( region.lower ) ); + + // Obviously, whenever we remove a region from the links, we need to check + // if the region even has any more links... otherwise it's clearly dead and + // needs to be removed entirely. + if ( region.links.isEmpty() ) { + regionIt.remove(); + } + region.lower = MIN_CROSS; } @@ -1646,11 +1711,11 @@ public class Mesh< T extends Region > { throw new IllegalStateException( "Vertex has less than 2 left edges!" ); } - final HalfEdge topLeft = leftGoing.get( 0 ).getSym(); - final HalfEdge bottomLeft = leftGoing.get( leftGoing.size() - 1 ).getSym(); + final HalfEdge topLeft = leftGoing.get( 0 ); + final HalfEdge bottomLeft = leftGoing.get( leftGoing.size() - 1 ); - final Partition top = lowerEdgeMap.remove( topLeft ); - final Partition bottom = upperEdgeMap.remove( bottomLeft ); + final Partition top = lowerEdgeMap.remove( topLeft.getSym() ); + final Partition bottom = upperEdgeMap.remove( bottomLeft.getSym() ); if ( top == null ) { throw new IllegalStateException( "Upper partition not found!" ); @@ -1658,7 +1723,7 @@ public class Mesh< T extends Region > { throw new IllegalStateException( "Lower partition not found!" ); } - chains.addAll( bottom.chains ); + top.chains.addAll( bottom.chains ); lowerEdgeMap.remove( bottom.upper ); // Merge the top and bottom partition @@ -1668,14 +1733,14 @@ public class Mesh< T extends Region > { lowerEdgeMap.put( top.lower, top ); // Update all visibility regions for the top and bottom partitions, separately - top.incrementLower( topLeft.getSym() ); - bottom.incrementUpper( bottomLeft.getSym() ); + top.incrementLower( topLeft ); + bottom.incrementUpper( bottomLeft ); // Merge the two partitions top.add( bottom ); // Add a new visibility region - top.add( event, new VisibilityRegion( bottomLeft.getSym(), topLeft.getSym() ) ); + top.add( event, new VisibilityRegion( bottomLeft, topLeft ) ); } // This vertex has both left and right going edges @@ -1688,13 +1753,13 @@ public class Mesh< T extends Region > { if ( interior.contains( lower ) ) { // There exists a partition below this vertex - final HalfEdge left = leftGoing.get( leftGoing.size() - 1 ).getSym(); + final HalfEdge left = leftGoing.get( leftGoing.size() - 1 ); final HalfEdge right = rightGoing.get( 0 ); final Partition partition = lowerEdgeMap.get( lower ); if ( partition != null ) { - if ( partition.upper != left ) { + if ( partition.upper != left.getSym() ) { throw new IllegalStateException( "Partition upper edge is inconsistent!" ); } @@ -1708,7 +1773,7 @@ public class Mesh< T extends Region > { partition.incrementUpper( right ); // Add a new region for this vertex - partition.add( event, new VisibilityRegion( left.getSym(), right ) ); + partition.add( event, new VisibilityRegion( left, right ) ); } else { throw new IllegalStateException( "Interior edge does not have a partition!" ); } @@ -1716,13 +1781,13 @@ public class Mesh< T extends Region > { if ( upper != null && interior.contains( upper.getSym() ) ) { // There exists a partition above this vertex - final HalfEdge left = leftGoing.get( 0 ).getSym(); + final HalfEdge left = leftGoing.get( 0 ); final HalfEdge right = rightGoing.get( rightGoing.size() - 1 ); final Partition partition = upperEdgeMap.get( upper ); if ( partition != null ) { - if ( partition.lower != left ) { + if ( partition.lower != left.getSym() ) { throw new IllegalStateException( "Partition lower edge is inconsistent!" ); } @@ -1735,7 +1800,7 @@ public class Mesh< T extends Region > { partition.incrementLower( right ); // Add a new region for this vertex - partition.add( event, new VisibilityRegion( left.getSym(), right ) ); + partition.add( event, new VisibilityRegion( right, left ) ); } else { throw new IllegalStateException( "Interior edge does not have a partition!" ); } @@ -1759,7 +1824,17 @@ public class Mesh< T extends Region > { System.out.println( "Found links: " + chains.size() ); Map< Vertex, Collection< Vertex > > mappings = new HashMap< Vertex, Collection< Vertex > >(); for ( final Chain c : chains ) { - System.out.println( c.getOrigin() + "\t to \t" + c.getDest() ); + System.out.println( c + ":\t" + c.links.get( 0 ) + "\t to \t" + c.links.get( 1 ) + "\t to \t" + c.links.get( 2 ) ); +// System.out.println( "\tIntersects with: " + c.intersections.size() ); + for ( final Chain i : c.intersections ) { +// System.out.println( "\t\t" + i + ":\t" + i.getOrigin() + "\t to \t" + i.getDest() ); + } + if ( c.previous != null ) { +// System.out.println( "\tPrev: " + c.previous ); + } + if ( c.next != null ) { +// System.out.println( "\tNext: " + c.next ); + } Collection< Vertex > destinations; if ( mappings.containsKey( c.getOrigin() ) ) { diff --git a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java index cd735f6..b48d792 100644 --- a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java +++ b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java @@ -279,17 +279,22 @@ public class MeshingTest2 extends JPanel { Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } ); mesh.addPolygon( new Polygon( Arrays.asList( - new Point( -1, -1 ), + new Point( -1, 0 ), + new Point( 1, -2 ), new Point( 1, -1 ), - new Point( 1, 1 ), - new Point( -1, 1 ) + new Point( 2, -1 ), + new Point( 1, 0 ), + new Point( 1, 1 ) ) ), RegionRuleWinding.CLOCKWISE ); mesh.simplify(); mesh.generateRegions(); - return mesh.mesh(); + final Collection< EdgePolygon > polys = mesh.mesh(); + chains = mesh.chains; + + return polys; } private static List< Facet > generateFacetsFor( AABB box ) {