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

@@ -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 >();
}
}