From 586fb04c02c52f98e346f9e609afdf5b6152b279 Mon Sep 17 00:00:00 2001 From: BananaPuncher714 Date: Fri, 23 May 2025 02:17:25 -0400 Subject: [PATCH] Introduce fuzzy iterating when finding chains; Found another bug when detecting chain collisions --- .../bananapuncher714/mesh/Mesh.java | 130 +++++- .../minietest/MeshingTest2.java | 373 +++++++++++++----- .../minietest/MeshingTest3.java | 196 +++++++++ 3 files changed, 598 insertions(+), 101 deletions(-) create mode 100644 src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest3.java diff --git a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java index 09573b9..541828b 100644 --- a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java +++ b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/mesh/Mesh.java @@ -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; diff --git a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java index f92e825..e465e6f 100644 --- a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java +++ b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest2.java @@ -2,6 +2,7 @@ package com.aaaaahhhhhhh.bananapuncher714.minietest; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics; @@ -24,24 +25,24 @@ import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; -import java.util.function.Function; import javax.swing.JButton; +import javax.swing.JComboBox; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import org.bukkit.util.Vector; import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain; -import com.aaaaahhhhhhh.bananapuncher714.mesh.HalfEdge; import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshEventHandler; import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon; import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment; import com.aaaaahhhhhhh.bananapuncher714.mesh.Vector2d; -import com.aaaaahhhhhhh.bananapuncher714.mesh.Vertex; import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding; import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple; import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule; @@ -73,26 +74,31 @@ public class MeshingTest2 extends JPanel { private double scale = 8; - private PlaneData data; - private int stringBoardX = -100; private int stringBoardY = 20; + final private List< Plane > planes; + final private PlaneData[] data; + int index = -1; + + private JLabel statusBar; + private JComboBox< String > selectionBox; + public static void main( String[] args ) { if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) { System.out.println( "Found " + CHUNK_DIR.list().length + " files" ); - for ( File file : CHUNK_DIR.listFiles() ) { - List< Plane > planes = mesh( file ); +// for ( File file : CHUNK_DIR.listFiles() ) { +// List< Plane > planes = mesh( file ); - Plane draw = null; +// Plane draw = null; - System.out.println( "Planes: " + planes.size() ); - for ( Plane plane : planes ) { - if ( plane.polygons.size() > 100 ) { - draw = plane; - break; - } - } +// System.out.println( "Planes: " + planes.size() ); +// int planeIndex = 0; +// for ( planeIndex = 0; planeIndex < planes.size(); ++planeIndex ) { +// if ( planes.get( planeIndex ).polygons.size() > 100 ) { +// break; +// } +// } // Collections.sort( planes, ( a, b ) -> Integer.compare( b.polygons.size(), a.polygons.size() ) ); // draw = planes.get( 4 ); @@ -100,7 +106,7 @@ public class MeshingTest2 extends JPanel { // Select a random plane to draw // draw = planes.get( new Random().nextInt( planes.size() ) ); - System.out.println( "Draw is " + draw ); +// System.out.println( "Draw is " + draw ); // Attempt to mesh all planes // try { // test( planes ); @@ -109,20 +115,43 @@ public class MeshingTest2 extends JPanel { // System.out.println( "Draw is now " + draw ); // } - final PlaneData data = process( draw ); - final Collection< Polygon > polys = triangulate( draw ); +// final PlaneData data = process( draw ); +// final Collection< Polygon > polys = triangulate( draw ); // final Collection< Polygon > polys = test(); +// System.out.println( "Polygon count: " + data.polygons.size() ); - System.out.println( "Polygon count: " + polys.size() ); - - SwingUtilities.invokeLater( new Runnable() { - @Override - public void run() { - new MeshingTest2( data ); - } - } ); - break; - } +// final int startingIndex = planeIndex; +// SwingUtilities.invokeLater( new Runnable() { +// @Override +// public void run() { +// new MeshingTest2( planes ).setIndex( startingIndex ).start();; +// } +// } ); +// break; +// } + + List< Plane > masterPlanes = new ArrayList< Plane >(); +// System.out.println( "Chunk files: " + CHUNK_DIR.listFiles().length ); +// int limit = 1; +// for ( File file : CHUNK_DIR.listFiles() ) { +// masterPlanes.addAll( mesh( file ) ); +// if ( --limit <= 0 ) { +// break; +// } else { +// System.out.println( "Remaining: " + limit ); +// } +// } + final List< Plane > planes = mesh( new File( CHUNK_DIR, "world,-2,1" ) ); + masterPlanes.add( planes.get( 218 ) ); + +// masterPlanes.add( getTestPlane() ); + + SwingUtilities.invokeLater( new Runnable() { + @Override + public void run() { + new MeshingTest2( masterPlanes ).start(); + } + } ); } else { System.err.println( "No such directory exists: " + CHUNK_DIR ); } @@ -247,11 +276,44 @@ public class MeshingTest2 extends JPanel { @Override public void onPreChainMergeEvent( Collection< Chain > chains ) { data.selectedChains = chains; + + final List< Chain > sorted = new ArrayList< Chain >( chains ); + Collections.sort( sorted, ( a, b ) -> { + final double diff = a.getStart().getX() - b.getStart().getX(); + if ( Math.abs( diff ) < 1e-7 ) { + return Double.compare( a.getStart().getY(), b.getStart().getY() ); + } + return Double.compare( diff, 0 ); + } ); + for ( Chain chain : sorted ) { + System.out.println( "c: " + chain.getPoints() ); + } + + final Set< Point > points = new HashSet< Point >(); + for ( Chain chain : chains ) { + for ( int i = 1; i < chain.getPoints().size() - 1; ++i ) { + if ( !points.add( chain.getPoints().get( i ) ) ) { + System.out.println( "Intersection at " + chain.getPoints().get( i ) ); + } + } + } } } ); data.polygons = mesh.mesh(); +// final List< Point > points = new ArrayList< Point >( data.vertices ); +// Collections.sort( points, ( a, b ) -> { +// final int x = Double.compare( a.getX(), b.getX() ); +// if ( x == 0 ) { +// return Double.compare( a.getY(), b.getY() ); +// } +// return x; +// } ); +// for ( Point v : points ) { +// System.out.println( v.getX() + ", " + v.getY() ); +// } + System.out.println( "Took " + ( end - start ) + "ms" ); return data; } else { @@ -306,8 +368,24 @@ public class MeshingTest2 extends JPanel { } } - private static Collection< Polygon > test() { - Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } ); + private static PlaneData test() { + final PlaneData data = new PlaneData(); + final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } ); + mesh.addHandler( new MeshEventHandler() { + @Override + public void onChainGenerationEvent( Collection< Chain > chains ) { + data.chains = chains; + } + + @Override + public void onPreChainMergeEvent( Collection< Chain > chains ) { + data.selectedChains = chains; + + for ( Chain chain : chains ) { + System.out.println( "c: " + chain.getPoints() ); + } + } + } ); // mesh.addPolygon( new Polygon( Arrays.asList( // new Point( -1, 0 ), @@ -428,39 +506,64 @@ public class MeshingTest2 extends JPanel { // new Point( 2.8151429293905887, -2.747294403063162 ) // ) ), RegionRuleWinding.CLOCKWISE ); - mesh.addPolygon( new Polygon( Arrays.asList( - new Point( 0, 0 ), +// mesh.addPolygon( new Polygon( Arrays.asList( +// new Point( 0, 0 ), +// new Point( 1, 0 ), +// new Point( 1, 1 ), +// new Point( 0, 1 ) +// ) ), RegionRuleWinding.CLOCKWISE ); +// mesh.addPolygon( new Polygon( Arrays.asList( +// new Point( 0, 2 ), +// new Point( 1, 2 ), +// new Point( 1, 3 ), +// new Point( 0, 3 ) +// ) ), RegionRuleWinding.CLOCKWISE ); +// mesh.addPolygon( new Polygon( Arrays.asList( +// new Point( -1, -1 ), +// new Point( 2, -1 ), +// new Point( 2, 4 ), +// new Point( -1, 4 ) +// ) ), RegionRuleWinding.CLOCKWISE ); + + data.polygons = mesh.mesh(); + data.vertices = mesh.getVertices(); + data.edges = mesh.getEdges(); + + return data; + } + + private static Plane getTestPlane() { + final Plane plane = new Plane(); + +// plane.polygons.add( new Polygon( Arrays.asList( +// new Point( 1, 0 ), +// new Point( 2, 1 ), +// new Point( 3, 0 ), +// new Point( 4, 1 ), +// new Point( 3, 2 ), +// new Point( 4, 3 ), +// new Point( 3, 4 ), +// new Point( 2, 3 ), +// new Point( 1, 4 ), +// new Point( 0, 3 ), +// new Point( 1, 2 ), +// new Point( 0, 1 ) + plane.polygons.add( new Polygon( Arrays.asList( new Point( 1, 0 ), - new Point( 1, 1 ), - new Point( 0, 1 ) - ) ), RegionRuleWinding.CLOCKWISE ); - mesh.addPolygon( new Polygon( Arrays.asList( - new Point( 0, 2 ), + new Point( 2, 1 ), + new Point( 3, 0 ), + new Point( 4, 1 ), + new Point( 3, 2 ), + new Point( 4, 3 ), + new Point( 3, 4 ), + new Point( 2, 3 ), + new Point( 1, 4 ), + new Point( 0, 3 ), new Point( 1, 2 ), - new Point( 1, 3 ), - new Point( 0, 3 ) - ) ), RegionRuleWinding.CLOCKWISE ); - mesh.addPolygon( new Polygon( Arrays.asList( - new Point( -1, -1 ), - new Point( 2, -1 ), - new Point( 2, 4 ), - new Point( -1, 4 ) - ) ), RegionRuleWinding.CLOCKWISE ); + new Point( 0, 1 ) + ) ) ); - mesh.simplify(); - - mesh.generateRegions(); - - try { - final Collection< Polygon > polys = mesh.mesh(); - return polys; - } catch ( Exception e ) { - e.printStackTrace(); - } - - final Collection< Polygon > polys = mesh.mesh(); - - return polys; + return plane; } private static List< Facet > generateFacetsFor( AABB box ) { @@ -562,8 +665,59 @@ public class MeshingTest2 extends JPanel { } } - public MeshingTest2( PlaneData data ) { - this.data = data; + public MeshingTest2( List< Plane > data ) { + this.planes = data; + this.data = new PlaneData[ data.size() ]; + } + + private MeshingTest2 setIndex( final int index ) { + // TODO Synchronize this + final int planeCount = planes.size(); + final int newIndex = ( ( ( index % planeCount ) + planeCount ) % planeCount ); + if ( this.index != newIndex ) { + this.index = newIndex; + + new Thread( () -> { getData( this::repaint ); } ).start(); + + if ( selectionBox != null ) { + selectionBox.setSelectedIndex( newIndex ); + } + } + + return this; + } + + private PlaneData getData( final Runnable callback ) { + if ( data[ index ] != null ) { + callback.run(); + return data[ index ]; + } else { + setStatus( "Loading..." ); + final PlaneData data = process( planes.set( index, null ) ); + setStatus( "Done!" ); + this.data[ index ] = data; + callback.run(); + return data; + } + } + + private void setStatus( final String status ) { + if ( statusBar != null ) { + statusBar.setText( status ); + } + } + + private MeshingTest2 preMesh() { + for ( int i = 0; i < planes.size(); ++i ) { + this.data[ i ] = process( planes.set( i, null ) ); + } + return this; + } + + private void start() { + if ( index == -1 ) { + setIndex( 0 ); + } f = new JFrame( "Drawing Board" ); f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); @@ -631,13 +785,45 @@ public class MeshingTest2 extends JPanel { }; } ); -// final JPanel taskbar = new JPanel(); -// taskbar.setLayout( new FlowLayout() ); -// -// taskbar.add( new JButton( "Previous" ) ); -// taskbar.add( new JButton( "Next" ) ); -// -// f.add( taskbar, BorderLayout.NORTH ); + final JPanel taskbar = new JPanel(); + taskbar.setLayout( new FlowLayout() ); + + { + final JComboBox< String > data = new JComboBox< String >(); + for ( int i = 0; i < planes.size(); ++i ) { + data.addItem( "Plane " + i ); + } + data.addActionListener( e -> { + setIndex( data.getSelectedIndex() ); + } ); + taskbar.add( data ); + + selectionBox = data; + } + + { + final JLabel label = new JLabel(); + label.setPreferredSize( new Dimension( 100, 16 ) ); + label.setHorizontalAlignment( SwingConstants.LEFT ); + taskbar.add( label ); + + statusBar = label; + } + + { + final JButton prev = new JButton( "Previous" ); + prev.addActionListener( e -> { setIndex( index - 1 ); } ); + taskbar.add( prev ); + } + + + { + final JButton prev = new JButton( "Next" ); + prev.addActionListener( e -> { setIndex( index + 1 ); } ); + taskbar.add( prev ); + } + + f.add( taskbar, BorderLayout.NORTH ); f.add( this ); @@ -665,18 +851,24 @@ public class MeshingTest2 extends JPanel { public void paintComponent( Graphics g ) { super.paintComponent( g ); + final PlaneData data = this.data[ index ]; + g.setColor( new Color( 200, 200, 200 ) ); g.drawLine( ( int ) ( scale * centerX ) + offsetX, 0, ( int ) ( scale * centerX ) + offsetX, getHeight() ); g.drawLine( 0, ( int ) ( scale * centerY ) + offsetY, getWidth(), ( int ) ( scale * centerY ) + offsetY ); g.setColor( Color.BLACK ); - int highestX = 40; if ( data != null ) { + int highestX = 40; if ( !data.edges.isEmpty() ) { Collection< Point > points = data.vertices; - highestX = ( int ) ( points.parallelStream() - .max( ( a, b ) -> { return Double.compare( a.getX(), b.getX() ); } ).get().getX() + 40.5 ); + if ( !data.polygons.isEmpty() ) { + highestX = ( int ) ( points.parallelStream() + .max( ( a, b ) -> { return Double.compare( a.getX(), b.getX() ); } ).get().getX() + 40.5 ); + } else { + highestX = 0; + } g.setColor( Color.BLACK ); for ( final Segment segment : data.edges ) { @@ -694,12 +886,9 @@ public class MeshingTest2 extends JPanel { final double diff = scale * 0.15; g.drawRect( ( int ) ( ( centerX + point.getX() + highestX ) * scale ) - ( int ) diff + offsetX, ( int ) ( ( centerY - point.getY() ) * scale ) - ( int ) diff + offsetY, ( int ) ( diff * 2 ), ( int ) ( diff * 2 ) ); } - - drawOnBoard( g, "Edge count: " + data.edges.size(), 0, 0 ); - drawOnBoard( g, "Vertex count: " + points.size(), 0, -5 ); } - if ( data.polygons != null ) { + { int count = 2; Random random = new Random( hashCode() ); @@ -730,12 +919,9 @@ public class MeshingTest2 extends JPanel { g.fillPolygon( filledX, filledY, points.size() ); ++count; } - - g.setColor( Color.MAGENTA ); - drawOnBoard( g, "Polygon count: " + data.polygons.size(), 0, -10 ); } - if ( data.chains != null ) { + { g.setColor( Color.RED ); for ( final Chain chain : data.chains ) { final Point p1 = chain.getStart(); @@ -749,10 +935,9 @@ public class MeshingTest2 extends JPanel { ); } - drawOnBoard( g, "Chain count: " + data.chains.size(), 0, -15 ); } - if ( data.selectedChains != null ) { + { g.setColor( Color.BLUE ); for ( final Chain chain : data.selectedChains ) { final Point p1 = chain.getStart(); @@ -765,8 +950,20 @@ public class MeshingTest2 extends JPanel { ( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY ); } - drawOnBoard( g, "Minimum chain count: " + data.selectedChains.size(), 0, -20 ); } + + g.setColor( Color.BLACK ); + drawOnBoard( g, "Plane index: " + index, 0, 10 ); + g.setColor( Color.CYAN ); + drawOnBoard( g, "Edge count: " + data.edges.size(), 0, 0 ); + g.setColor( Color.GREEN ); + drawOnBoard( g, "Vertex count: " + data.vertices.size(), 0, -5 ); + g.setColor( Color.MAGENTA ); + drawOnBoard( g, "Triangle count: " + data.polygons.size(), 0, -10 ); + g.setColor( Color.RED ); + drawOnBoard( g, "Total Chain count: " + data.chains.size(), 0, -15 ); + g.setColor( Color.BLUE ); + drawOnBoard( g, "Possible chain count: " + data.selectedChains.size(), 0, -20 ); } java.awt.Point p = MouseInfo.getPointerInfo().getLocation(); @@ -779,10 +976,10 @@ public class MeshingTest2 extends JPanel { } private static class PlaneData { - Collection< Point > vertices; - Collection< Segment > edges; - Collection< Chain > chains; - Collection< Chain > selectedChains; - Collection< Polygon > polygons; + Collection< Point > vertices = new HashSet< Point >(); + Collection< Segment > edges = new HashSet< Segment >(); + Collection< Chain > chains = new HashSet< Chain >(); + Collection< Chain > selectedChains = new HashSet< Chain >(); + Collection< Polygon > polygons = new HashSet< Polygon >(); } } \ No newline at end of file diff --git a/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest3.java b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest3.java new file mode 100644 index 0000000..1652dbd --- /dev/null +++ b/src/main/java/com/aaaaahhhhhhh/bananapuncher714/minietest/MeshingTest3.java @@ -0,0 +1,196 @@ +package com.aaaaahhhhhhh.bananapuncher714.minietest; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.util.Vector; + +import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh; +import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; +import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon; +import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding; +import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple; +import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule; +import com.aaaaahhhhhhh.bananapuncher714.minietest.MeshingTest2.AABB; +import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation; +import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Facet; +import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.MeshBuilder; +import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Plane; + +public class MeshingTest3 { + private static final File BASE = new File( System.getProperty( "user.dir" ) ); + private static final File CHUNK_DIR = new File( BASE, "chunks" ); + + public static void main( String[] args ) { + if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) { + System.out.println( "Found " + CHUNK_DIR.list().length + " files" ); +// for ( int i = 0; i < CHUNK_DIR.listFiles().length; ++i ) { +// final File file = CHUNK_DIR.listFiles()[ i ]; +// System.out.println( "Meshing " + file + "\t" + ( i + 1 ) + "/" + CHUNK_DIR.listFiles().length ); +// final List< Plane > planes = mesh( file ); +// planes.parallelStream().forEach( p -> { +// try { +// process( p ); +// } catch ( IllegalStateException e ) { +// e.printStackTrace(); +// +// semiProcess( p ); +// +// System.exit( 1 ); +// } +// } ); +// } + + final List< Plane > planes = mesh( new File( CHUNK_DIR, "world,-2,1" ) ); +// for ( int i = 0; i < planes.size(); ++i ) { +// System.out.println( "Meshing plane " + i ); +// process( planes.get( i ) ); +// } + + process( planes.get( 218 ) ); + } else { + System.err.println( "No such directory exists: " + CHUNK_DIR ); + } + } + + private static void process( final Plane plane ) { + if ( plane != null ) { + Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } ); + for ( Polygon poly : plane.polygons ) { + mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE ); + } + + mesh.meshify(); + } else { + System.out.println( "No data!" ); + } + } + + private static void semiProcess( final Plane plane ) { + + } + + private static List< Plane > mesh( File file ) { + String name = file.getName(); + String[] split = name.split( "," ); + ChunkLocation location = new ChunkLocation( split[ 0 ], Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) ); + + System.out.println( "Parsing chunk " + location ); + + // First parse the file to get a list of all bounding boxes that we can use + List< AABB > boxes = new ArrayList< AABB >(); + try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) { + String line; + while ( ( line = reader.readLine() ) != null ) { + if ( !line.isEmpty() ) { + String[] values = line.split( "," ); + double minX = Double.parseDouble( values[ 0 ] ); + double minY = Double.parseDouble( values[ 1 ] ); + double minZ = Double.parseDouble( values[ 2 ] ); + double maxX = Double.parseDouble( values[ 3 ] ); + double maxY = Double.parseDouble( values[ 4 ] ); + double maxZ = Double.parseDouble( values[ 5 ] ); + boxes.add( new AABB( minX, minY, minZ, maxX, maxY, maxZ ) ); + } + } + } catch ( FileNotFoundException e ) { + e.printStackTrace(); + return null; + } catch ( IOException e ) { + e.printStackTrace(); + return null; + } + + System.out.println( "Found " + boxes.size() + " boxes" ); + // Now that we have a bunch of bounding boxes, do whatever + + MeshBuilder builder = new MeshBuilder(); + for ( AABB box : boxes ) { + for ( Facet facet : generateFacetsFor( box ) ) { + builder.addFacet( facet ); + } + } + + return builder.planes; + } + + private static List< Facet > generateFacetsFor( AABB box ) { + List< Facet > facets = new ArrayList< Facet >(); + + Vector p1 = new Vector( box.xmin, box.ymin, box.zmin ); + Vector p2 = new Vector( box.xmin, box.ymin, box.zmax ); + Vector p3 = new Vector( box.xmin, box.ymax, box.zmin ); + Vector p4 = new Vector( box.xmin, box.ymax, box.zmax ); + Vector p5 = new Vector( box.xmax, box.ymin, box.zmin ); + Vector p6 = new Vector( box.xmax, box.ymin, box.zmax ); + Vector p7 = new Vector( box.xmax, box.ymax, box.zmin ); + Vector p8 = new Vector( box.xmax, box.ymax, box.zmax ); + + { + Facet facet = new Facet(); + facet.points.add( p1 ); + facet.points.add( p2 ); + facet.points.add( p4 ); + facet.points.add( p3 ); + facet.normal = new Vector( -1, 0, 0 ); + facets.add( facet ); + } + + { + Facet facet = new Facet(); + facet.points.add( p5 ); + facet.points.add( p6 ); + facet.points.add( p8 ); + facet.points.add( p7 ); + facet.normal = new Vector( 1, 0, 0 ); + facets.add( facet ); + } + + { + Facet facet = new Facet(); + facet.points.add( p1 ); + facet.points.add( p2 ); + facet.points.add( p6 ); + facet.points.add( p5 ); + facet.normal = new Vector( 0, -1, 0 ); + facets.add( facet ); + } + + { + Facet facet = new Facet(); + facet.points.add( p3 ); + facet.points.add( p4 ); + facet.points.add( p8 ); + facet.points.add( p7 ); + facet.normal = new Vector( 0, 1, 0 ); + facets.add( facet ); + } + + { + Facet facet = new Facet(); + facet.points.add( p1 ); + facet.points.add( p3 ); + facet.points.add( p7 ); + facet.points.add( p5 ); + facet.normal = new Vector( 0, 0, -1 ); + facets.add( facet ); + } + + { + Facet facet = new Facet(); + facet.points.add( p2 ); + facet.points.add( p4 ); + facet.points.add( p8 ); + facet.points.add( p6 ); + facet.normal = new Vector( 0, 0, 1 ); + facets.add( facet ); + } + + return facets; + } +}