Compare commits

...

14 Commits

Author SHA1 Message Date
5b4076edab Incorporate environment into the main plugin 2026-03-18 22:03:40 -04:00
3f4b4c6975 Create standalone physics plugin 2026-03-18 01:03:39 -04:00
70049922c5 Finish prototype mesh environment 2026-03-17 23:17:51 -04:00
45c65f4f78 Refactor and add basic sparse mesh implementation 2026-03-17 00:45:35 -04:00
95e374682b Partial refactor 2026-03-16 18:35:19 -04:00
14b1647c47 Fix each test and added READMEs 2026-03-15 18:56:59 -04:00
c2aa41fe58 Move each application to its own submodule
Removed JOML and Bukkit depednencies for the standalone applications
2026-03-15 15:16:42 -04:00
ce8165417b Initial cleanup and refactor 2026-03-14 23:03:06 -04:00
793d1e846a Add de/serialization for chunk meshes
Add half-baked loading and saving to avoid having to mesh the chunk each time
2025-05-31 05:13:11 -04:00
13c92dcb43 Added better chunk meshing
Fixed some collinear vertices not being scanned
Added live block mesh updates
2025-05-31 02:37:26 -04:00
d45d644b32 Change to use facet format for saving and processing chunks
Fixed bug where merging and splitting connected regions may result in a chain desync
Added spawn size to minie spawn command
Added live chunk generation
Use a smarter more conservative facet generation method for each chunk to reduce initial mesh simplification costs
2025-05-26 16:38:55 -04:00
7c49e004b7 Speedup the mesh simplification
Change EdgeSet to use LinkedHashSet for better iteration, potentially.
Map polygon points to existing vertices to reduce unnecessary vertex duplication
Attempt to merge overlapping edges initially before doing anything else when simplifying
Use tree sets instead of priority queues for constant time poll
Split intersection calculation method into two separate methods
Rework which edges are actively within the scan zone to reduce the amount of edges to check when looking for intersections. This should help make the entire algorithm closer to O(nlogn)
Removed intersection classes
Added method to resolve only collinear edges around a vertex
Added method to resolve edge intersections directly from the edge, rather than the positive side
Added simple Y check to see if two edges can even intersect
Added method to calculate absolute vector
Added test plane by default to MeshingTest2(the plane viewer)
2025-05-25 21:34:35 -04:00
83e3b9443b Removed sorting when triangulating
Properly determine the insertion edge when triangulation to avoid having to sort each vertex later
Synchronize the plane viewer to prevent incorrect index saving when switching planes too quickly
Use the shape instead of collision shape for summoned physics objects
2025-05-24 22:04:20 -04:00
9fcab219af Updated the plugin to mesh chunks properly; Use the visual shape for chunk generation 2025-05-24 03:57:21 -04:00
127 changed files with 8749 additions and 1876 deletions

7
.gitignore vendored
View File

@@ -2,8 +2,5 @@
.project .project
target target
.settings .settings
chunks data
new_chunks bin
images
chunk_models
chunk_models_new

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule ".git-submodules/spigot-docker-build-tools"]
path = .git-submodules/spigot-docker-build-tools
url = https://git.048596.world/banana/spigot-docker-build-tools.git

17
application/pom.xml Normal file
View File

@@ -0,0 +1,17 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-master</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>mc-mesh-application</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<modules>
<module>visualizer</module>
</modules>
</project>

View File

@@ -0,0 +1,9 @@
# Test 1
This test requires a directory called `chunks` in the current working directory,
filled with mAABB file that follow the naming convention: `<string>,<int>,<int>`.
The mAABB file format contains an arbitrary number of AABBs, with one line per each:
`<min-x> <min-y> <min-z> <max-x> <max-y> <max-z>`
This program should be ran via the command line with `java -jar`. It will process the
first file it finds and print out each plane and the associated properties with each one.

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-1</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshTest</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-1</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshTest</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest; package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@@ -8,12 +8,11 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bukkit.util.Vector; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Facet; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.MeshBuilder; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Plane;
public class MeshTest { public class MeshTest {
private static final File BASE = new File( System.getProperty( "user.dir" ) ); private static final File BASE = new File( System.getProperty( "user.dir" ) );
@@ -34,7 +33,7 @@ public class MeshTest {
private static void doStuff( File file ) { private static void doStuff( File file ) {
String name = file.getName(); String name = file.getName();
String[] split = name.split( "," ); String[] split = name.split( "," );
ChunkLocation location = new ChunkLocation( split[ 0 ], Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) ); Point location = new Point( Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
System.out.println( "Parsing chunk " + location ); System.out.println( "Parsing chunk " + location );
@@ -66,7 +65,6 @@ public class MeshTest {
// Now that we have a bunch of bounding boxes, do whatever // Now that we have a bunch of bounding boxes, do whatever
MeshBuilder builder = new MeshBuilder(); MeshBuilder builder = new MeshBuilder();
int i = 0;
for ( AABB box : boxes ) { for ( AABB box : boxes ) {
for ( Facet facet : generateFacetsFor( box ) ) { for ( Facet facet : generateFacetsFor( box ) ) {
builder.addFacet( facet ); builder.addFacet( facet );
@@ -105,14 +103,14 @@ public class MeshTest {
private static List< Facet > generateFacetsFor( AABB box ) { private static List< Facet > generateFacetsFor( AABB box ) {
List< Facet > facets = new ArrayList< Facet >(); List< Facet > facets = new ArrayList< Facet >();
Vector p1 = new Vector( box.xmin, box.ymin, box.zmin ); Vector3d p1 = new Vector3d( box.xmin, box.ymin, box.zmin );
Vector p2 = new Vector( box.xmin, box.ymin, box.zmax ); Vector3d p2 = new Vector3d( box.xmin, box.ymin, box.zmax );
Vector p3 = new Vector( box.xmin, box.ymax, box.zmin ); Vector3d p3 = new Vector3d( box.xmin, box.ymax, box.zmin );
Vector p4 = new Vector( box.xmin, box.ymax, box.zmax ); Vector3d p4 = new Vector3d( box.xmin, box.ymax, box.zmax );
Vector p5 = new Vector( box.xmax, box.ymin, box.zmin ); Vector3d p5 = new Vector3d( box.xmax, box.ymin, box.zmin );
Vector p6 = new Vector( box.xmax, box.ymin, box.zmax ); Vector3d p6 = new Vector3d( box.xmax, box.ymin, box.zmax );
Vector p7 = new Vector( box.xmax, box.ymax, box.zmin ); Vector3d p7 = new Vector3d( box.xmax, box.ymax, box.zmin );
Vector p8 = new Vector( box.xmax, box.ymax, box.zmax ); Vector3d p8 = new Vector3d( box.xmax, box.ymax, box.zmax );
{ {
Facet facet = new Facet(); Facet facet = new Facet();
@@ -120,7 +118,7 @@ public class MeshTest {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p3 ); facet.points.add( p3 );
facet.normal = new Vector( -1, 0, 0 ); facet.normal = new Vector3d( -1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -130,7 +128,7 @@ public class MeshTest {
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 1, 0, 0 ); facet.normal = new Vector3d( 1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -140,7 +138,7 @@ public class MeshTest {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, -1, 0 ); facet.normal = new Vector3d( 0, -1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -150,7 +148,7 @@ public class MeshTest {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.normal = new Vector( 0, 1, 0 ); facet.normal = new Vector3d( 0, 1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -160,7 +158,7 @@ public class MeshTest {
facet.points.add( p3 ); facet.points.add( p3 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, 0, -1 ); facet.normal = new Vector3d( 0, 0, -1 );
facets.add( facet ); facets.add( facet );
} }
@@ -170,7 +168,7 @@ public class MeshTest {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.normal = new Vector( 0, 0, 1 ); facet.normal = new Vector3d( 0, 0, 1 );
facets.add( facet ); facets.add( facet );
} }
@@ -183,7 +181,7 @@ public class MeshTest {
AABB( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax ) { AABB( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax ) {
this.xmin = xmin; this.xmin = xmin;
this.ymax = ymin; this.ymin = ymin;
this.zmin = zmin; this.zmin = zmin;
this.xmax = xmax; this.xmax = xmax;

View File

@@ -0,0 +1,15 @@
# Test 2
This test requires a directory called `chunks` in the current working directory,
filled with mAABB files that follow the naming convention: `<string>,<int>,<int>`.
The mAABB file format contains an arbitrary number of AABBs, with one line per each:
`<min-x> <min-y> <min-z> <max-x> <max-y> <max-z>`
This program is a visual application. It will process the first file it finds, and
convert the group of AABBs to planes. It will then mesh each individual plane and
allow the user to browse:
- The final tesselated plane
- A wireframe of the tesselated plane
- A wireframe of the tesselated plane with chain calculation
- Each triangle of the final product
- The tesselation by-product values

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-2</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest2</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-2</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest2</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest; package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
@@ -17,6 +17,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@@ -24,6 +25,7 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComboBox; import javax.swing.JComboBox;
@@ -33,23 +35,25 @@ import javax.swing.JPanel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.bukkit.util.Vector; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Chain;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh.MeshChainEventHandler;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh.MeshPartitionEventHandler;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshEventHandler; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Segment;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Vector2d;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Vector2d; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Facet; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.MeshBuilder; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Plane;
/**
* Chunk data meshing visualizer
*/
public class MeshingTest2 extends JPanel { public class MeshingTest2 extends JPanel {
private static final File BASE = new File( System.getProperty( "user.dir" ) ); private static final File BASE = new File( System.getProperty( "user.dir" ) );
private static final File CHUNK_DIR = new File( BASE, "chunks" ); private static final File CHUNK_DIR = new File( BASE, "chunks" );
@@ -83,6 +87,8 @@ public class MeshingTest2 extends JPanel {
private JLabel statusBar; private JLabel statusBar;
private JComboBox< String > selectionBox; private JComboBox< String > selectionBox;
private ReentrantLock lock = new ReentrantLock();
public static void main( String[] args ) { public static void main( String[] args ) {
if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) { if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) {
System.out.println( "Found " + CHUNK_DIR.list().length + " files" ); System.out.println( "Found " + CHUNK_DIR.list().length + " files" );
@@ -129,7 +135,10 @@ public class MeshingTest2 extends JPanel {
// break; // break;
// } // }
List< Plane > masterPlanes = new ArrayList< Plane >(); final List< Plane > masterPlanes = new ArrayList< Plane >();
System.out.println( "Adding test plane" );
masterPlanes.addAll( getTestPlanes() );
System.out.println( "Chunk files: " + CHUNK_DIR.listFiles().length ); System.out.println( "Chunk files: " + CHUNK_DIR.listFiles().length );
int limit = 1; int limit = 1;
for ( File file : CHUNK_DIR.listFiles() ) { for ( File file : CHUNK_DIR.listFiles() ) {
@@ -140,12 +149,11 @@ public class MeshingTest2 extends JPanel {
System.out.println( "Remaining: " + limit ); System.out.println( "Remaining: " + limit );
} }
} }
// final List< Plane > planes = mesh( new File( CHUNK_DIR, "world,-4,-6" ) );
// masterPlanes.add( planes.get( 177 ) );
// masterPlanes.addAll( planes );
// masterPlanes.add( getTestPlane() ); // final List< Plane > planes = mesh( new File( CHUNK_DIR, "world,10,-6" ) );
// masterPlanes.add( planes.get( 27 ) );
// masterPlanes.addAll( planes );
SwingUtilities.invokeLater( new Runnable() { SwingUtilities.invokeLater( new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -160,7 +168,7 @@ public class MeshingTest2 extends JPanel {
private static List< Plane > mesh( File file ) { private static List< Plane > mesh( File file ) {
String name = file.getName(); String name = file.getName();
String[] split = name.split( "," ); String[] split = name.split( "," );
ChunkLocation location = new ChunkLocation( split[ 0 ], Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) ); Point location = new Point( Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
System.out.println( "Parsing chunk " + location ); System.out.println( "Parsing chunk " + location );
@@ -258,16 +266,23 @@ public class MeshingTest2 extends JPanel {
System.out.println( "After simplify vertex count: " + mesh.getVertices().size() ); System.out.println( "After simplify vertex count: " + mesh.getVertices().size() );
System.out.println( "After simplify edge count: " + ( mesh.getEdgeCount() / 2 ) ); System.out.println( "After simplify edge count: " + ( mesh.getEdgeCount() / 2 ) );
mesh.generateRegions();
long end = System.currentTimeMillis();
data.vertices = mesh.getVertices(); data.vertices = mesh.getVertices();
data.edges = mesh.getEdges(); data.edges = mesh.getEdges();
try {
mesh.generateRegions();
data.vertices = mesh.getVertices();
data.edges = mesh.getEdges();
} catch ( Exception e ) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() ); System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) ); System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
mesh.addHandler( new MeshEventHandler() { mesh.addChainHandler( new MeshChainEventHandler() {
@Override @Override
public void onChainGenerationEvent( Collection< Chain > chains ) { public void onChainGenerationEvent( Collection< Chain > chains ) {
data.chains = chains; data.chains = chains;
@@ -298,7 +313,9 @@ public class MeshingTest2 extends JPanel {
// } // }
// } // }
} }
} );
mesh.addPartitionHandler( new MeshPartitionEventHandler() {
@Override @Override
public void onPartitionEvent( Collection< Polygon > polygons ) { public void onPartitionEvent( Collection< Polygon > polygons ) {
data.polygons = polygons; data.polygons = polygons;
@@ -379,7 +396,7 @@ public class MeshingTest2 extends JPanel {
private static PlaneData test() { private static PlaneData test() {
final PlaneData data = new PlaneData(); final PlaneData data = new PlaneData();
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } ); final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
mesh.addHandler( new MeshEventHandler() { mesh.addChainHandler( new MeshChainEventHandler() {
@Override @Override
public void onChainGenerationEvent( Collection< Chain > chains ) { public void onChainGenerationEvent( Collection< Chain > chains ) {
data.chains = chains; data.chains = chains;
@@ -540,8 +557,13 @@ public class MeshingTest2 extends JPanel {
return data; return data;
} }
private static Plane getTestPlane() { private static Collection< Plane > getTestPlanes() {
final Plane plane = new Plane(); final Collection< Plane > planes = new ArrayDeque< Plane >();
{
final Plane plane = new Plane();
plane.normal = new Vector3d( 0, 0, 1 );
plane.point = new Vector3d( 1, 0, 0 );
// plane.polygons.add( new Polygon( Arrays.asList( // plane.polygons.add( new Polygon( Arrays.asList(
// new Point( 1, 0 ), // new Point( 1, 0 ),
@@ -556,35 +578,141 @@ public class MeshingTest2 extends JPanel {
// new Point( 0, 3 ), // new Point( 0, 3 ),
// new Point( 1, 2 ), // new Point( 1, 2 ),
// new Point( 0, 1 ) // new Point( 0, 1 )
plane.polygons.add( new Polygon( Arrays.asList( // plane.polygons.add( new Polygon( Arrays.asList(
new Point( 1, 0 ), // new Point( 1, 0 ),
new Point( 2, 1 ), // new Point( 2, 1 ),
new Point( 3, 0 ), // new Point( 3, 0 ),
new Point( 4, 1 ), // new Point( 4, 1 ),
new Point( 3, 2 ), // new Point( 3, 2 ),
new Point( 4, 3 ), // new Point( 4, 3 ),
new Point( 3, 4 ), // new Point( 3, 4 ),
new Point( 2, 3 ), // new Point( 2, 3 ),
new Point( 1, 4 ), // new Point( 1, 4 ),
new Point( 0, 3 ), // new Point( 0, 3 ),
new Point( 1, 2 ), // new Point( 1, 2 ),
new Point( 0, 1 ) // new Point( 0, 1 )
) ) ); // ) ) );
return plane; plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, -1 ),
new Point( 1, -1 ),
new Point( 1, 1 ),
new Point( -1, 1 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, -1 ),
new Point( 1, -1 ),
new Point( 1, 1 ),
new Point( -1, 1 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, -1 ),
new Point( 1, -1 ),
new Point( 1, 1 ),
new Point( -1, 1 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, 1 ),
new Point( 1, 1 ),
new Point( 1, 3 ),
new Point( -1, 3 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -2, -1 ),
new Point( -1, -1 ),
new Point( -1, 2 ),
new Point( -2, 2 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -4, -2 ),
new Point( -1, -2 ),
new Point( -1, 1.5 ),
new Point( -4, 1.5 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -3, 0 ),
new Point( 3, 0 ),
new Point( -1.5, -3 ),
new Point( 0, 1.5 ),
new Point( 1.5, -3 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, 0 ),
new Point( 0, 1.5 ),
new Point( 1, 0 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( 1, 0 ),
new Point( 0, -2 ),
new Point( -1, 0 )
) ) );
planes.add( plane );
}
{
final Plane plane = new Plane();
plane.normal = new Vector3d( 0, 0, 1 );
plane.point = new Vector3d( 1, 0, 0 );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( 0, 0 ),
new Point( 3, 0 ),
new Point( 3, 2 ),
new Point( 2, 2 ),
new Point( 2, 1 ),
new Point( 1, 1 ),
new Point( 1, 2 ),
new Point( 0, 2 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( 1, 1 ),
new Point( 2, 1 ),
new Point( 2, 2 ),
new Point( 1, 2 )
) ) );
planes.add( plane );
}
{
final Plane plane = new Plane();
plane.normal = new Vector3d( 0, 0, 1 );
plane.point = new Vector3d( 1, 0, 0 );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( 0, 0 ),
new Point( 3, 0 ),
new Point( 3, 2 ),
new Point( 0, 2 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( 1, 1 ),
new Point( 2, 1 ),
new Point( 2, 2 ),
new Point( 1, 2 )
) ) );
planes.add( plane );
}
return planes;
} }
private static List< Facet > generateFacetsFor( AABB box ) { private static List< Facet > generateFacetsFor( AABB box ) {
List< Facet > facets = new ArrayList< Facet >(); List< Facet > facets = new ArrayList< Facet >();
Vector p1 = new Vector( box.xmin, box.ymin, box.zmin ); Vector3d p1 = new Vector3d( box.xmin, box.ymin, box.zmin );
Vector p2 = new Vector( box.xmin, box.ymin, box.zmax ); Vector3d p2 = new Vector3d( box.xmin, box.ymin, box.zmax );
Vector p3 = new Vector( box.xmin, box.ymax, box.zmin ); Vector3d p3 = new Vector3d( box.xmin, box.ymax, box.zmin );
Vector p4 = new Vector( box.xmin, box.ymax, box.zmax ); Vector3d p4 = new Vector3d( box.xmin, box.ymax, box.zmax );
Vector p5 = new Vector( box.xmax, box.ymin, box.zmin ); Vector3d p5 = new Vector3d( box.xmax, box.ymin, box.zmin );
Vector p6 = new Vector( box.xmax, box.ymin, box.zmax ); Vector3d p6 = new Vector3d( box.xmax, box.ymin, box.zmax );
Vector p7 = new Vector( box.xmax, box.ymax, box.zmin ); Vector3d p7 = new Vector3d( box.xmax, box.ymax, box.zmin );
Vector p8 = new Vector( box.xmax, box.ymax, box.zmax ); Vector3d p8 = new Vector3d( box.xmax, box.ymax, box.zmax );
{ {
Facet facet = new Facet(); Facet facet = new Facet();
@@ -592,7 +720,7 @@ public class MeshingTest2 extends JPanel {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p3 ); facet.points.add( p3 );
facet.normal = new Vector( -1, 0, 0 ); facet.normal = new Vector3d( -1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -602,7 +730,7 @@ public class MeshingTest2 extends JPanel {
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 1, 0, 0 ); facet.normal = new Vector3d( 1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -612,7 +740,7 @@ public class MeshingTest2 extends JPanel {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, -1, 0 ); facet.normal = new Vector3d( 0, -1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -622,7 +750,7 @@ public class MeshingTest2 extends JPanel {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 0, 1, 0 ); facet.normal = new Vector3d( 0, 1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -632,7 +760,7 @@ public class MeshingTest2 extends JPanel {
facet.points.add( p3 ); facet.points.add( p3 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, 0, -1 ); facet.normal = new Vector3d( 0, 0, -1 );
facets.add( facet ); facets.add( facet );
} }
@@ -642,7 +770,7 @@ public class MeshingTest2 extends JPanel {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.normal = new Vector( 0, 0, 1 ); facet.normal = new Vector3d( 0, 0, 1 );
facets.add( facet ); facets.add( facet );
} }
@@ -679,23 +807,24 @@ public class MeshingTest2 extends JPanel {
} }
private MeshingTest2 setIndex( final int index ) { private MeshingTest2 setIndex( final int index ) {
// TODO Synchronize this
final int planeCount = planes.size(); final int planeCount = planes.size();
final int newIndex = ( ( ( index % planeCount ) + planeCount ) % planeCount ); final int newIndex = ( ( ( index % planeCount ) + planeCount ) % planeCount );
lock.lock();
if ( this.index != newIndex ) { if ( this.index != newIndex ) {
this.index = newIndex; this.index = newIndex;
new Thread( () -> { getData( this::repaint ); } ).start();
if ( selectionBox != null ) { if ( selectionBox != null ) {
selectionBox.setSelectedIndex( newIndex ); selectionBox.setSelectedIndex( newIndex );
} }
new Thread( () -> { getData( this.index, this::repaint ); } ).start();
} }
lock.unlock();
return this; return this;
} }
private PlaneData getData( final Runnable callback ) { private PlaneData getData( final int index, final Runnable callback ) {
if ( data[ index ] != null ) { if ( data[ index ] != null ) {
callback.run(); callback.run();
return data[ index ]; return data[ index ];

View File

@@ -0,0 +1,9 @@
# Test 1
This test requires a directory called `chunks` in the current working directory,
filled with mAABB files that follow the naming convention: `<string>,<int>,<int>`.
The mAABB file format contains an arbitrary number of AABBs, with one line per each:
`<min-x> <min-y> <min-z> <max-x> <max-y> <max-z>`
This program should be ran via the command line with `java -jar`. It will tesselate all
the files it can find as fast as possible, then output the time results.

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-3</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest3</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-3</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest3</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest; package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@@ -6,22 +6,25 @@ import java.io.FileNotFoundException;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.util.Vector; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.minietest.MeshingTest2.AABB; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Facet;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Plane;
/**
* Mesh speed test
*/
public class MeshingTest3 { public class MeshingTest3 {
private static final File BASE = new File( System.getProperty( "user.dir" ) ); private static final File BASE = new File( System.getProperty( "user.dir" ) );
private static final File CHUNK_DIR = new File( BASE, "chunks" ); private static final File CHUNK_DIR = new File( BASE, "chunks" );
@@ -29,10 +32,18 @@ public class MeshingTest3 {
public static void main( String[] args ) { public static void main( String[] args ) {
if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) { if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) {
System.out.println( "Found " + CHUNK_DIR.list().length + " files" ); 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 ]; final long allStart = System.currentTimeMillis();
System.out.println( "Meshing " + file + "\t" + ( i + 1 ) + "/" + CHUNK_DIR.listFiles().length ); final AtomicInteger index = new AtomicInteger( 0 );
final List< Plane > planes = mesh( file ); final Collection< File > files = Arrays.asList( CHUNK_DIR.listFiles() );
files.parallelStream().forEach( f -> {
final StringBuilder builder = new StringBuilder();
builder.append( "Meshing file: " + f + "\n" );
final long start = System.currentTimeMillis();
final List< Plane > planes = mesh( f, builder );
planes.parallelStream().forEach( p -> { planes.parallelStream().forEach( p -> {
try { try {
process( p ); process( p );
@@ -42,15 +53,43 @@ public class MeshingTest3 {
System.exit( 1 ); System.exit( 1 );
} }
} ); } );
}
long time = System.currentTimeMillis() - start;
builder.append( "\tTook " + time + "ms\n" );
builder.append( "\tCompleted " + index.incrementAndGet() + "/" + files.size() );
System.out.println( builder.toString() );
} );
System.out.println( "Took a total of " + ( System.currentTimeMillis() - allStart ) + "ms" );
// final List< Plane > planes = mesh( new File( CHUNK_DIR, "world,-4,-6" ) ); // 123 // for ( int i = 0; i < CHUNK_DIR.listFiles().length; ++i ) {
// final File file = CHUNK_DIR.listFiles()[ i ];
// System.out.println( ( i + 1 ) + "/" + CHUNK_DIR.listFiles().length + ":\tMeshing " + file );
// long start = System.currentTimeMillis();
// final List< Plane > planes = mesh( file, null );
// planes.parallelStream().forEach( p -> {
// try {
// process( p );
// } catch ( IllegalStateException e ) {
// e.printStackTrace();
//
// System.exit( 1 );
// }
// } );
//
// long time = System.currentTimeMillis() - start;
//
// System.out.println( "\tTook " + time + "ms" );
// }
// final List< Plane > planes = mesh( new File( CHUNK_DIR, "world,-10,-10" ) ); // 25
// for ( int i = 0; i < planes.size(); ++i ) { // for ( int i = 0; i < planes.size(); ++i ) {
// System.out.println( "Meshing plane " + i ); // System.out.println( "Meshing plane " + i );
// process( planes.get( i ) ); // process( planes.get( i ) );
// } // }
// process( planes.get( 177 ) ); // process( planes.get( 27 ) );
} else { } else {
System.err.println( "No such directory exists: " + CHUNK_DIR ); System.err.println( "No such directory exists: " + CHUNK_DIR );
} }
@@ -69,12 +108,10 @@ public class MeshingTest3 {
} }
} }
private static List< Plane > mesh( File file ) { private static List< Plane > mesh( File file, final StringBuilder stringBuilder ) {
String name = file.getName(); String name = file.getName();
String[] split = name.split( "," ); String[] split = name.split( "," );
ChunkLocation location = new ChunkLocation( split[ 0 ], Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) ); Point location = new Point( 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 // First parse the file to get a list of all bounding boxes that we can use
List< AABB > boxes = new ArrayList< AABB >(); List< AABB > boxes = new ArrayList< AABB >();
@@ -100,7 +137,13 @@ public class MeshingTest3 {
return null; return null;
} }
System.out.println( "Found " + boxes.size() + " boxes" ); if ( stringBuilder != null ) {
stringBuilder.append( "\tParsing chunk " + location + "\n" );
stringBuilder.append( "\tFound " + boxes.size() + " boxes\n" );
} else {
System.out.println( "\tParsing chunk " + location );
System.out.println( "\tFound " + boxes.size() + " boxes" );
}
// Now that we have a bunch of bounding boxes, do whatever // Now that we have a bunch of bounding boxes, do whatever
MeshBuilder builder = new MeshBuilder(); MeshBuilder builder = new MeshBuilder();
@@ -116,14 +159,14 @@ public class MeshingTest3 {
private static List< Facet > generateFacetsFor( AABB box ) { private static List< Facet > generateFacetsFor( AABB box ) {
List< Facet > facets = new ArrayList< Facet >(); List< Facet > facets = new ArrayList< Facet >();
Vector p1 = new Vector( box.xmin, box.ymin, box.zmin ); Vector3d p1 = new Vector3d( box.xmin, box.ymin, box.zmin );
Vector p2 = new Vector( box.xmin, box.ymin, box.zmax ); Vector3d p2 = new Vector3d( box.xmin, box.ymin, box.zmax );
Vector p3 = new Vector( box.xmin, box.ymax, box.zmin ); Vector3d p3 = new Vector3d( box.xmin, box.ymax, box.zmin );
Vector p4 = new Vector( box.xmin, box.ymax, box.zmax ); Vector3d p4 = new Vector3d( box.xmin, box.ymax, box.zmax );
Vector p5 = new Vector( box.xmax, box.ymin, box.zmin ); Vector3d p5 = new Vector3d( box.xmax, box.ymin, box.zmin );
Vector p6 = new Vector( box.xmax, box.ymin, box.zmax ); Vector3d p6 = new Vector3d( box.xmax, box.ymin, box.zmax );
Vector p7 = new Vector( box.xmax, box.ymax, box.zmin ); Vector3d p7 = new Vector3d( box.xmax, box.ymax, box.zmin );
Vector p8 = new Vector( box.xmax, box.ymax, box.zmax ); Vector3d p8 = new Vector3d( box.xmax, box.ymax, box.zmax );
{ {
Facet facet = new Facet(); Facet facet = new Facet();
@@ -131,7 +174,7 @@ public class MeshingTest3 {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p3 ); facet.points.add( p3 );
facet.normal = new Vector( -1, 0, 0 ); facet.normal = new Vector3d( -1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -141,7 +184,7 @@ public class MeshingTest3 {
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 1, 0, 0 ); facet.normal = new Vector3d( 1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -151,7 +194,7 @@ public class MeshingTest3 {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, -1, 0 ); facet.normal = new Vector3d( 0, -1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -161,7 +204,7 @@ public class MeshingTest3 {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 0, 1, 0 ); facet.normal = new Vector3d( 0, 1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -171,7 +214,7 @@ public class MeshingTest3 {
facet.points.add( p3 ); facet.points.add( p3 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, 0, -1 ); facet.normal = new Vector3d( 0, 0, -1 );
facets.add( facet ); facets.add( facet );
} }
@@ -181,10 +224,25 @@ public class MeshingTest3 {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.normal = new Vector( 0, 0, 1 ); facet.normal = new Vector3d( 0, 0, 1 );
facets.add( facet ); facets.add( facet );
} }
return facets; return facets;
} }
static class AABB {
double xmin, ymin, zmin;
double xmax, ymax, zmax;
AABB( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax ) {
this.xmin = xmin;
this.ymin = ymin;
this.zmin = zmin;
this.xmax = xmax;
this.ymax = ymax;
this.zmax = zmax;
}
}
} }

View File

@@ -0,0 +1,10 @@
# Test 1
This test requires a directory called `chunks` in the current working directory,
filled with mAABB file that follow the naming convention: `<string>,<int>,<int>`.
This test will create a directory called `chunk_models` containing `ply2` files.
The mAABB file format contains an arbitrary number of AABBs, with one line per each:
`<min-x> <min-y> <min-z> <max-x> <max-y> <max-z>`
This program should be ran via the command line with `java -jar`. It will tesselate each
file and save them in `ply2` format in the `chunk_models` directory. This will take a while.

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-4</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest4</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-4</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest4</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,436 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
/**
* Mesh chunk data to ply2 format
*/
public class MeshingTest4 {
private static final File BASE = new File( System.getProperty( "user.dir" ) );
private static final File CHUNK_DIR = new File( BASE, "chunks" );
private static final File MODEL_DIR = new File( BASE, "chunk_models" );
public static void main( String[] args ) {
if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) {
System.out.println( "Found " + CHUNK_DIR.list().length + " files" );
// Omega mesh time
// omegaMesh( CHUNK_DIR, new File( MODEL_DIR, "omega" ) );
final long allStart = System.currentTimeMillis();
final AtomicInteger index = new AtomicInteger( 0 );
final Collection< File > files = Arrays.asList( CHUNK_DIR.listFiles() );
files.parallelStream().forEach( f -> {
final StringBuilder builder = new StringBuilder();
builder.append( "Meshing file: " + f + "\n" );
final long start = System.currentTimeMillis();
final List< Plane > planes = mesh( f, builder );
Collection< Facet > facets = planes.parallelStream().flatMap( p -> process( p ).parallelStream().map( p::convert ) ).collect( Collectors.toSet() );
savePly2( new File( MODEL_DIR, f.getName() + ".ply" ), facets );
saveStl( new File( MODEL_DIR, f.getName() + ".stl" ), facets );
final long time = System.currentTimeMillis() - start;
builder.append( "\tTook " + time + "ms\n" );
builder.append( "\tCompleted " + index.incrementAndGet() + "/" + files.size() );
System.out.println( builder.toString() );
} );
System.out.println( "Took a total of " + ( System.currentTimeMillis() - allStart ) );
// for ( int i = 0; i < CHUNK_DIR.listFiles().length; ++i ) {
// final File file = CHUNK_DIR.listFiles()[ i ];
// System.out.println( ( i + 1 ) + "/" + CHUNK_DIR.listFiles().length + ":\tMeshing " + file );
// final long start = System.currentTimeMillis();
// final StringBuilder builder = new StringBuilder();
// final List< Plane > planes = mesh( file, builder );
// System.out.println( builder.toString() );
// Collection< Facet > facets = planes.parallelStream().flatMap( p -> process( p ).parallelStream().map( p::convert ) ).collect( Collectors.toSet() );
// savePly2( new File( MODEL_DIR, file.getName() + ".ply" ), facets );
// saveStl( new File( MODEL_DIR, file.getName() + ".stl" ), facets );
// long time = System.currentTimeMillis() - start;
// System.out.println( "\tTook " + time + "ms" );
// }
} else {
System.err.println( "No such directory exists: " + CHUNK_DIR );
}
}
private static void savePly2( final File file, Collection< Facet > facets ) {
file.getParentFile().mkdirs();
if ( file.exists() ) {
file.delete();
}
class VectorRef {
int index;
}
class Triangle {
List< VectorRef > refs = new ArrayList< VectorRef >();
}
Map< Vector3d, VectorRef > vertices = new HashMap< Vector3d, VectorRef >();
Collection< Triangle > triangles = new HashSet< Triangle >();
// Convert each facet to a triangle
for ( final Facet facet : facets ) {
if ( facet.points.size() != 3 ) {
System.out.println( "Warning: Facet is not a triangle!" );
}
final Triangle triangle = new Triangle();
for ( final Vector3d vec : facet.points ) {
VectorRef ref = null;
for ( final Entry< Vector3d, VectorRef > entry : vertices.entrySet() ) {
final Vector3d existingVec = entry.getKey();
if ( existingVec.distanceSquared( vec ) < 1e-8 ) {
ref = entry.getValue();
break;
}
}
if ( ref == null ) {
ref = new VectorRef();
vertices.put( vec, ref );
}
triangle.refs.add( ref );
}
triangles.add( triangle );
}
// Sort the vertices
final List< Entry< Vector3d, VectorRef > > sorted = new ArrayList< Entry< Vector3d, VectorRef > >( vertices.entrySet() );
Collections.sort( sorted, ( aEntry, bEntry ) -> {
final Vector3d a = aEntry.getKey();
final Vector3d b = bEntry.getKey();
final double xDiff = a.getX() - b.getX();
if ( xDiff == 0 ) {
final double yDiff = a.getY() - b.getY();
if ( yDiff == 0 ) {
return Double.compare( a.getZ(), b.getZ() );
} else {
return Double.compare( yDiff, 0 );
}
} else {
return Double.compare( xDiff, 0 );
}
} );
try ( PrintWriter writer = new PrintWriter( file ) ) {
writer.println( "ply" );
writer.println( "format ascii 1.0" );
writer.println( "comment Created by java tess" );
writer.println( "element vertex " + sorted.size() );
writer.println( "property float x" );
writer.println( "property float y" );
writer.println( "property float z" );
writer.println( "element face " + triangles.size() );
writer.println( "element property list uchar uint vertex_indices" );
writer.println( "end_header" );
// Write vertices
for ( int i = 0; i < sorted.size(); ++i ) {
final Entry< Vector3d, VectorRef > entry = sorted.get( i );
entry.getValue().index = i;
final Vector3d vector = entry.getKey();
writer.println( String.format( "%f %f %f", vector.getX(), vector.getY(), vector.getZ() ) );
}
for ( final Triangle triangle : triangles ) {
final StringBuilder builder = new StringBuilder();
builder.append( triangle.refs.size() );
for ( final VectorRef ref : triangle.refs ) {
builder.append( " " );
builder.append( ref.index );
}
writer.println( builder.toString() );
}
System.out.println( "\tWriting " + triangles.size() + " triangles and " + sorted.size() + " vertices to " + file );
} catch ( FileNotFoundException e ) {
e.printStackTrace();
}
}
private static void saveStl( final File file, Collection< Facet > facets ) {
file.getParentFile().mkdirs();
if ( file.exists() ) {
file.delete();
}
try ( PrintWriter writer = new PrintWriter( file ) ) {
writer.println( "solid test" );
for ( Facet f : facets ) {
writer.println( "facet normal " + f.normal.getX() + " " + f.normal.getY() + " " + f.normal.getZ() );
writer.println( "outer loop" );
for ( Vector3d p : f.points ) {
writer.println( "vertex " + p.getX() + " " + p.getY() + " " + p.getZ() );
}
writer.println( "endloop" );
writer.println( "endfacet" );
}
writer.println( "endsolid test");
} catch ( FileNotFoundException e ) {
e.printStackTrace();
}
}
private static void omegaMesh( final File directory, final File output ) {
final List< AABB > allBoxes = new ArrayList< AABB >();
for ( int i = 0; i < directory.listFiles().length; ++i ) {
final File file = directory.listFiles()[ i ];
System.out.println( ( i + 1 ) + "/" + directory.listFiles().length + ": Getting meshes for: " + file );
allBoxes.addAll( getBoxes( file ) );
}
System.out.println( "Gathered " + allBoxes.size() + " boxes" );
final MeshBuilder builder = new MeshBuilder();
int boxCount = 0;
for ( final AABB box : allBoxes ) {
for ( final Facet facet : generateFacetsFor( box ) ) {
builder.addFacet( facet );
}
if ( ++boxCount % 100_000 == 0 ) {
System.out.println( "Added box " + boxCount + "/" + allBoxes.size() + "\t" + ( boxCount / ( double ) allBoxes.size() ) + "%" );
}
}
System.out.println( "Starting to mesh " + builder.planes.size() + " planes" );
final long start = System.currentTimeMillis();
final AtomicInteger counter = new AtomicInteger();
Collection< Facet > resultFacets = builder.planes.parallelStream().flatMap( p -> {
final Stream< Facet > facets = process( p ).parallelStream().map( p::convert );
System.out.println( "Finished " + counter.incrementAndGet() + "/" + builder.planes.size() );
return facets;
} ).collect( Collectors.toSet() );
savePly2( new File( output.getAbsolutePath() + ".ply" ), resultFacets );
saveStl( new File( output.getAbsolutePath() + ".stl" ), resultFacets );
System.out.println( "\tTook " + ( System.currentTimeMillis() - start ) + "ms" );
}
private static Collection< Polygon > 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 );
}
return mesh.meshify();
} else {
System.out.println( "No data!" );
return Collections.emptySet();
}
}
private static List< Plane > mesh( File file, final StringBuilder stringBuilder ) {
String name = file.getName();
String[] split = name.split( "," );
Point location = new Point( Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
// 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;
}
// 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 );
}
}
if ( stringBuilder != null ) {
stringBuilder.append( "\tParsing chunk " + location + "\n" );
stringBuilder.append( "\tFound " + boxes.size() + " boxes and " + builder.planes.size() + " planes\n" );
} else {
System.out.println( "\tParsing chunk " + location );
System.out.println( "\tFound " + boxes.size() + " boxes and " + builder.planes.size() + " planes" );
}
return builder.planes;
}
private static List< AABB > getBoxes( final File file ) {
final String name = file.getName();
final String[] split = name.split( "," );
final int chunkX = Integer.parseInt( split[ 1 ] );
final int chunkZ = Integer.parseInt( split[ 2 ] );
final int blockX = chunkX << 4;
final int blockZ = chunkZ << 4;
// First parse the file to get a list of all bounding boxes that we can use
final 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 + blockX, minY, minZ + blockZ, maxX + blockX, maxY, maxZ + blockZ ) );
}
}
} catch ( FileNotFoundException e ) {
e.printStackTrace();
return Collections.emptyList();
} catch ( IOException e ) {
e.printStackTrace();
return Collections.emptyList();
}
return boxes;
}
private static List< Facet > generateFacetsFor( AABB box ) {
List< Facet > facets = new ArrayList< Facet >();
Vector3d p1 = new Vector3d( box.xmin, box.ymin, box.zmin );
Vector3d p2 = new Vector3d( box.xmin, box.ymin, box.zmax );
Vector3d p3 = new Vector3d( box.xmin, box.ymax, box.zmin );
Vector3d p4 = new Vector3d( box.xmin, box.ymax, box.zmax );
Vector3d p5 = new Vector3d( box.xmax, box.ymin, box.zmin );
Vector3d p6 = new Vector3d( box.xmax, box.ymin, box.zmax );
Vector3d p7 = new Vector3d( box.xmax, box.ymax, box.zmin );
Vector3d p8 = new Vector3d( 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 Vector3d( -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 Vector3d( 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 Vector3d( 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 Vector3d( 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 Vector3d( 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 Vector3d( 0, 0, 1 );
facets.add( facet );
}
return facets;
}
static class AABB {
double xmin, ymin, zmin;
double xmax, ymax, zmax;
AABB( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax ) {
this.xmin = xmin;
this.ymin = ymin;
this.zmin = zmin;
this.xmax = xmax;
this.ymax = ymax;
this.zmax = zmax;
}
}
}

View File

@@ -0,0 +1,16 @@
# Test 1
This test requires a directory called `facets` in the current working directory,
filled with facet files that follow the naming convention: `<string>,<int>,<int>`.
The facet file format contains an arbitrary number of facets, with each facet following
the given format:
```
<vertex-count> <normal-x> <normal-y> <normal-z>
<vertex-x> <vertex-y> <vertex-z>
...
```
The intial line of the vertex count and normals are followed by an extra line for each
vertex, containing the x, y and z coordinates of that vertex.
This program should be ran via the command line with `java -jar`. It will tesselate all
the files it can find as fast as possible, then output the time results.

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-5</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest5</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-5</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest5</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,177 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
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.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
/**
* Mesh speed test for facets
*/
public class MeshingTest5 {
private static final File BASE = new File( System.getProperty( "user.dir" ) );
private static final File FACET_DIR = new File( BASE, "facets" );
private static Collection< Facet > facets = Collections.synchronizedCollection( new LinkedHashSet< Facet >() );
public static void main( String[] args ) {
if ( FACET_DIR.exists() && FACET_DIR.isDirectory() ) {
System.out.println( "Found " + FACET_DIR.list().length + " files" );
final long allStart = System.currentTimeMillis();
final AtomicInteger index = new AtomicInteger( 0 );
final Collection< File > files = Arrays.asList( FACET_DIR.listFiles() );
files.parallelStream().forEach( f -> {
final StringBuilder builder = new StringBuilder();
builder.append( "Meshing file: " + f + "\n" );
final long start = System.currentTimeMillis();
final List< Plane > planes = mesh( f, builder );
planes.parallelStream().forEach( p -> {
try {
process( p );
} catch ( IllegalStateException e ) {
e.printStackTrace();
System.exit( 1 );
}
} );
long time = System.currentTimeMillis() - start;
builder.append( "\tTook " + time + "ms\n" );
builder.append( "\tCompleted " + index.incrementAndGet() + "/" + files.size() );
System.out.println( builder.toString() );
} );
System.out.println( "Took a total of " + ( System.currentTimeMillis() - allStart ) + "ms" );
// for ( int i = 0; i < FACET_DIR.listFiles().length; ++i ) {
// final File file = FACET_DIR.listFiles()[ i ];
// System.out.println( ( i + 1 ) + "/" + FACET_DIR.listFiles().length + ":\tMeshing " + file );
// long start = System.currentTimeMillis();
// final List< Plane > planes = mesh( file, null );
// planes.parallelStream().forEach( p -> {
// try {
// process( p );
// } catch ( IllegalStateException e ) {
// e.printStackTrace();
//
// System.exit( 1 );
// }
// } );
//
// long time = System.currentTimeMillis() - start;
//
// System.out.println( "\tTook " + time + "ms" );
// }
// final List< Plane > planes = mesh( new File( FACET_DIR, "world,-1,2.facet" ), null ); // 25
// for ( int i = 0; i < planes.size(); ++i ) {
// System.out.println( "Meshing plane " + i );
// process( planes.get( i ) );
// }
// process( planes.get( 73 ) );
} else {
System.err.println( "No such directory exists: " + FACET_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 );
}
synchronized( facets ) {
facets.addAll( plane.convert( mesh.meshify() ) );
}
} else {
System.out.println( "No data!" );
}
}
private static List< Plane > mesh( File file, final StringBuilder stringBuilder ) {
final String name = file.getName().substring( 0, file.getName().indexOf( '.' ) );
final String[] split = name.split( "," );
final Point location = new Point( Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
// First parse the file to get a list of all facets
final List< Facet > facets = new ArrayList< Facet >();
try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
String line;
while ( ( line = reader.readLine() ) != null ) {
if ( !line.isEmpty() ) {
String[] values = line.split( " " );
final int facetCount = Integer.parseInt( values[ 0 ] );
final double nx = Double.parseDouble( values[ 1 ] );
final double ny = Double.parseDouble( values[ 2 ] );
final double nz = Double.parseDouble( values[ 3 ] );
final Facet facet = new Facet();
facet.normal = new Vector3d( nx, ny, nz );
int point = 0;
while ( point < facetCount && ( line = reader.readLine() ) != null ) {
if ( !line.isEmpty() ) {
String[] values2 = line.split( " " );
final double px = Double.parseDouble( values2[ 0 ] );
final double py = Double.parseDouble( values2[ 1 ] );
final double pz = Double.parseDouble( values2[ 2 ] );
facet.points.add( new Vector3d( px, py, pz ) );
++point;
}
}
facets.add( facet );
}
}
} catch ( FileNotFoundException e ) {
e.printStackTrace();
return null;
} catch ( IOException e ) {
e.printStackTrace();
return null;
}
if ( stringBuilder != null ) {
stringBuilder.append( "\tParsing chunk " + location + "\n" );
stringBuilder.append( "\tFound " + facets.size() + " facets\n" );
} else {
System.out.println( "\tParsing chunk " + location );
System.out.println( "\tFound " + facets.size() + " facets" );
}
// Now that we have a bunch of bounding boxes, do whatever
MeshBuilder builder = new MeshBuilder();
for ( Facet facet : facets ) {
builder.addFacet( facet );
}
return builder.planes;
}
}

View File

@@ -0,0 +1,22 @@
# Test 1
This test requires a directory called `facets` in the current working directory,
filled with facet files that follow the naming convention: `<string>,<int>,<int>`.
The facet file format contains an arbitrary number of facets, with each facet following
the given format:
```
<vertex-count> <normal-x> <normal-y> <normal-z>
<vertex-x> <vertex-y> <vertex-z>
...
```
The intial line of the vertex count and normals are followed by an extra line for each
vertex, containing the x, y and z coordinates of that vertex.
This program is a visual application. It will process the first file it finds, and
convert the group of AABBs to planes. It will then mesh each individual plane and
allow the user to browse:
- The final tesselated plane
- A wireframe of the tesselated plane
- A wireframe of the tesselated plane with chain calculation
- Each triangle of the final product
- The tesselation by-product values

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-6</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest6</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-6</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest6</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,989 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
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.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;
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 com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Chain;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh.MeshChainEventHandler;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh.MeshPartitionEventHandler;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Segment;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Vector2d;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
/**
* Facet meshing visualizer
*/
public class MeshingTest6 extends JPanel {
private static final File BASE = new File( System.getProperty( "user.dir" ) );
private static final File FACET_DIR = new File( BASE, "facets" );
JFrame f;
// private int windowWidth = 1200;
// private int windowHeight = 1000;
private int windowWidth = 1200;
private int windowHeight = 800;
// private int centerX = 600;
// private int centerY = 400;
private int offsetX = windowWidth >> 1;
private int offsetY = windowHeight >> 1;
private double centerX = 0;
private double centerY = 0;
private double scale = 8;
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;
private ReentrantLock lock = new ReentrantLock();
public static void main( String[] args ) {
if ( FACET_DIR.exists() && FACET_DIR.isDirectory() ) {
System.out.println( "Found " + FACET_DIR.list().length + " files" );
// for ( File file : FACET_DIR.listFiles() ) {
// List< Plane > planes = mesh( file );
// Plane draw = null;
// 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 );
// Select a random plane to draw
// 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 );
// }
// final PlaneData data = process( draw );
// final Collection< Polygon > polys = triangulate( draw );
// final Collection< Polygon > polys = test();
// System.out.println( "Polygon count: " + data.polygons.size() );
// final int startingIndex = planeIndex;
// SwingUtilities.invokeLater( new Runnable() {
// @Override
// public void run() {
// new MeshingTest2( planes ).setIndex( startingIndex ).start();;
// }
// } );
// break;
// }
final List< Plane > masterPlanes = new ArrayList< Plane >();
System.out.println( "Facet files: " + FACET_DIR.listFiles().length );
int limit = 1;
for ( File file : FACET_DIR.listFiles() ) {
masterPlanes.addAll( mesh( file ) );
if ( --limit <= 0 ) {
break;
} else {
System.out.println( "Remaining: " + limit );
}
}
// final List< Plane > planes = mesh( new File( FACET_DIR, "world,-1,2.facet" ) );
// masterPlanes.add( planes.get( 73 ) );
// masterPlanes.addAll( planes );
System.out.println( "Adding test plane" );
masterPlanes.add( getTestPlane() );
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
new MeshingTest6( masterPlanes ).start();
}
} );
} else {
System.err.println( "No such directory exists: " + FACET_DIR );
}
}
private static List< Plane > mesh( File file ) {
final String name = file.getName().substring( 0, file.getName().indexOf( '.' ) );
final String[] split = name.split( "," );
final Point location = new Point( Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
System.out.println( "Parsing chunk " + location );
// First parse the file to get a list of all facets
final List< Facet > facets = new ArrayList< Facet >();
try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
String line;
while ( ( line = reader.readLine() ) != null ) {
if ( !line.isEmpty() ) {
String[] values = line.split( " " );
final int facetCount = Integer.parseInt( values[ 0 ] );
final double nx = Double.parseDouble( values[ 1 ] );
final double ny = Double.parseDouble( values[ 2 ] );
final double nz = Double.parseDouble( values[ 3 ] );
final Facet facet = new Facet();
facet.normal = new Vector3d( nx, ny, nz );
int point = 0;
while ( point < facetCount && ( line = reader.readLine() ) != null ) {
if ( !line.isEmpty() ) {
String[] values2 = line.split( " " );
final double px = Double.parseDouble( values2[ 0 ] );
final double py = Double.parseDouble( values2[ 1 ] );
final double pz = Double.parseDouble( values2[ 2 ] );
facet.points.add( new Vector3d( px, py, pz ) );
++point;
}
}
facets.add( facet );
}
}
} catch ( FileNotFoundException e ) {
e.printStackTrace();
return null;
} catch ( IOException e ) {
e.printStackTrace();
return null;
}
// Now that we have a bunch of facets, do whatever
System.out.println( "Found " + facets.size() + " facets" );
MeshBuilder builder = new MeshBuilder();
for ( Facet facet : facets ) {
builder.addFacet( facet );
}
return builder.planes;
}
public static class PolygonException extends RuntimeException {
Plane plane;
PolygonException( Plane plane ) {
this.plane = plane;
}
Plane getPlane() {
return plane;
}
}
private static void test( final Collection< Plane > planes ) {
final long processAllStart = System.currentTimeMillis();
planes.parallelStream().forEach( plane -> {
try {
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
for ( Polygon poly : plane.polygons ) {
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
}
long start = System.currentTimeMillis();
mesh.simplify();
mesh.generateRegions();
final Collection< Polygon > polys = mesh.copyOf().mesh();
long end = System.currentTimeMillis();
System.out.println( plane.polygons.size() + " to " + polys.size() + ":\t " + ( end - start ) + "ms" );
} catch ( IllegalStateException e ) {
e.printStackTrace();
throw new PolygonException( plane );
}
} );
final long processAllEnd = System.currentTimeMillis();
System.out.println( "Took " + ( processAllEnd - processAllStart ) + "ms to process " + planes.size() + " planes" );
}
private static PlaneData process( final Plane plane ) {
if ( plane != null ) {
final PlaneData data = new PlaneData();
System.out.println( "Norm:\t" + plane.normal );
System.out.println( "Ref:\t" + plane.point );
System.out.println( "Size:\t" + plane.polygons.size() );
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
for ( Polygon poly : plane.polygons ) {
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
}
System.out.println( "Initial vertex count: " + mesh.getVertices().size() );
System.out.println( "Initial edge count: " + ( mesh.getEdgeCount() / 2 ) );
long start = System.currentTimeMillis();
mesh.simplify();
System.out.println( "After simplify vertex count: " + mesh.getVertices().size() );
System.out.println( "After simplify edge count: " + ( mesh.getEdgeCount() / 2 ) );
data.vertices = mesh.getVertices();
data.edges = mesh.getEdges();
try {
mesh.generateRegions();
data.vertices = mesh.getVertices();
data.edges = mesh.getEdges();
} catch ( Exception e ) {
e.printStackTrace();
return data;
}
long end = System.currentTimeMillis();
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
mesh.addChainHandler( new MeshChainEventHandler() {
@Override
public void onChainGenerationEvent( Collection< Chain > chains ) {
data.chains = chains;
}
@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 Collection< 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 ) );
}
}
}
}
} );
mesh.addPartitionHandler( new MeshPartitionEventHandler() {
@Override
public void onPartitionEvent( Collection< Polygon > polygons ) {
data.polygons = polygons;
}
} );
try {
// If the chains are the issue, set this to false and see if it still meshes
mesh.setMergeChains( true );
final Collection< Polygon > triangles = mesh.mesh();
if ( !triangles.isEmpty() ) {
data.polygons = triangles;
}
} catch ( IllegalStateException e ) {
e.printStackTrace();
}
// 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 {
System.out.println( "No data!" );
return null;
}
}
private static Collection< Polygon > triangulate( final Plane plane ) {
if ( plane != null ) {
System.out.println( "Norm:\t" + plane.normal );
System.out.println( "Ref:\t" + plane.point );
System.out.println( "Size:\t" + plane.polygons.size() );
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
for ( Polygon poly : plane.polygons ) {
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
}
System.out.println( "Initial vertex count: " + mesh.getVertices().size() );
System.out.println( "Initial edge count: " + ( mesh.getEdgeCount() / 2 ) );
long start = System.currentTimeMillis();
mesh.simplify();
System.out.println( "After simplify vertex count: " + mesh.getVertices().size() );
System.out.println( "After simplify edge count: " + ( mesh.getEdgeCount() / 2 ) );
mesh.generateRegions();
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
// Make sure this works
mesh = mesh.copyOf();
Collection< Polygon > polys = new HashSet< Polygon >();
try {
polys = mesh.mesh();
} catch ( IllegalStateException e ) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println( "Took " + ( end - start ) + "ms" );
return polys;
} else {
System.out.println( "No data!" );
return Collections.emptySet();
}
}
private static PlaneData test() {
final PlaneData data = new PlaneData();
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
mesh.addChainHandler( new MeshChainEventHandler() {
@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 ),
// new Point( 1, -2 ),
// new Point( 1, -1 ),
// new Point( 2, -1 ),
// new Point( 1, 0 ),
// new Point( 1, 1 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 0, 0 ),
// new Point( 5, 0 ),
// new Point( 5, 1 ),
// new Point( 4, 1 ),
// new Point( 4, 2 ),
// new Point( 3, 2 ),
// new Point( 3, 3 ),
// new Point( 2, 3 ),
// new Point( 2, 4 ),
// new Point( 0, 4 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 0, 0 ),
// new Point( 2, 0 ),
// new Point( 2, 1 ),
// new Point( 1, 1 ),
// new Point( 1, 2 ),
// new Point( 2, 2 ),
// new Point( 2, 4 ),
// new Point( 1, 4 ),
// new Point( 1, 3 ),
// new Point( 0, 3 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 0, 0 ),
// new Point( 3, 0 ),
// new Point( 3, 1 ),
// new Point( 4, 1 ),
// new Point( 4, 2 ),
// new Point( 2, 2 ),
// new Point( 2, 1 ),
// new Point( 1, 1 ),
// new Point( 0, 1 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 0, 0 ),
// new Point( 2, 0 ),
// new Point( 2, 1 ),
// new Point( 3, 1 ),
// new Point( 3, 2 ),
// new Point( 2, 2 ),
// new Point( 2, 5 ),
// new Point( 1, 5 ),
// new Point( 1, 7 ),
// new Point( 0, 7 ),
// new Point( 0, 4 ),
// new Point( 1, 4 ),
// new Point( 1, 1 ),
// new Point( 0, 1 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 1, 0 ),
// new Point( 6, 0 ),
// new Point( 6, 1 ),
// new Point( 4, 1 ),
// new Point( 4, 2 ),
// new Point( 2, 2 ),
// new Point( 2, 3 ),
// new Point( 0, 3 ),
// new Point( 0, 1 ),
// new Point( 1, 1 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 3, 1 ),
// new Point( 3, 0 ),
// new Point( 10, 0 ),
// new Point( 10, 6 ),
// new Point( 9, 6 ),
// new Point( 9, 4 ),
// new Point( 8, 4 ),
// new Point( 8, 3 ),
// new Point( 5, 3 ),
// new Point( 5, 2 ),
// new Point( 0, 2 ),
// new Point( 0, 1 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 7, 2 ),
// new Point( 9, 2 ),
// new Point( 9, 3 ),
// new Point( 7, 3 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 0, 0 ),
// new Point( 6, 1 ),
// new Point( 7, 2 ),
// new Point( 1, 1 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 2, 2 ),
// new Point( 8, 3 ),
// new Point( 9, 4 ),
// new Point( 3, 3 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 2.816104467407629, -3.7472939407853763 ),
// new Point( 2.815383313894849, -2.9972942874937156 ),
// new Point( 2.0028836894955497, -2.9980755371325607 ),
// new Point( 2.0036048430083304, -3.7480751904242213 )
// ) ), RegionRuleWinding.CLOCKWISE );
// mesh.addPolygon( new Polygon( Arrays.asList(
// new Point( 2.8144217758778085, -1.9972947497715015 ),
// new Point( 2.0019221514785093, -1.998075999410347 ),
// new Point( 2.00264330499129, -2.748075652702007 ),
// new Point( 2.8151429293905887, -2.747294403063162 )
// ) ), RegionRuleWinding.CLOCKWISE );
// 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.normal = new Vector3d( 0, 0, 1 );
plane.point = new Vector3d( 1, 0, 0 );
// 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( 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, -1 ),
new Point( 1, -1 ),
new Point( 1, 1 ),
new Point( -1, 1 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, -1 ),
new Point( 1, -1 ),
new Point( 1, 1 ),
new Point( -1, 1 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, -1 ),
new Point( 1, -1 ),
new Point( 1, 1 ),
new Point( -1, 1 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, 1 ),
new Point( 1, 1 ),
new Point( 1, 3 ),
new Point( -1, 3 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -2, -1 ),
new Point( -1, -1 ),
new Point( -1, 2 ),
new Point( -2, 2 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -4, -2 ),
new Point( -1, -2 ),
new Point( -1, 1.5 ),
new Point( -4, 1.5 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -3, 0 ),
new Point( 3, 0 ),
new Point( -1.5, -3 ),
new Point( 0, 1.5 ),
new Point( 1.5, -3 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( -1, 0 ),
new Point( 0, 1.5 ),
new Point( 1, 0 )
) ) );
plane.polygons.add( new Polygon( Arrays.asList(
new Point( 1, 0 ),
new Point( 0, -2 ),
new Point( -1, 0 )
) ) );
return plane;
}
public MeshingTest6( List< Plane > data ) {
this.planes = data;
this.data = new PlaneData[ data.size() ];
}
private MeshingTest6 setIndex( final int index ) {
final int planeCount = planes.size();
final int newIndex = ( ( ( index % planeCount ) + planeCount ) % planeCount );
lock.lock();
if ( this.index != newIndex ) {
this.index = newIndex;
if ( selectionBox != null ) {
selectionBox.setSelectedIndex( newIndex );
}
new Thread( () -> { getData( this.index, this::repaint ); } ).start();
}
lock.unlock();
return this;
}
private PlaneData getData( final int index, 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 MeshingTest6 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 );
final MouseAdapter adapter = new MouseAdapter() {
private boolean dragging = false;
private double initX, initY;
private int dragX, dragY;
private double scroll = Math.log( scale );
@Override
public void mousePressed( MouseEvent e ) {
dragging = true;
initX = centerX;
initY = centerY;
dragX = e.getXOnScreen();
dragY = e.getYOnScreen();
}
@Override
public void mouseReleased( MouseEvent e ) {
dragging = false;
}
@Override
public void mouseDragged( MouseEvent e ) {
if ( dragging ) {
centerX = initX + ( ( e.getXOnScreen() - dragX ) / scale );
centerY = initY + ( ( e.getYOnScreen() - dragY ) / scale );
repaint();
}
}
@Override
public void mouseWheelMoved( MouseWheelEvent e ) {
if ( e.getWheelRotation() < 0 ) {
scroll += e.isControlDown() ? 0.1 : 0.5;
} else {
scroll -= e.isControlDown() ? 0.1 : 0.5;
}
scale = Math.exp( scroll );
repaint();
}
@Override
public void mouseMoved( MouseEvent e ) {
super.mouseMoved( e );
repaint();
}
};
addMouseListener( adapter );
addMouseMotionListener( adapter );
addMouseWheelListener( adapter );
f.addComponentListener( new ComponentAdapter() {
public void componentResized( ComponentEvent e ) {
offsetX = getWidth() >> 1;
offsetY = getHeight() >> 1;
};
} );
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 );
f.setSize( windowWidth, windowHeight );
f.setVisible( true );
f.setResizable( true );
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
private static Vector2d rotate( Vector2d a, double angle ) {
double cos = Math.cos( angle );
double sin = Math.sin( angle );
double ax = a.getX() * cos - a.getY() * sin;
double ay = a.getX() * sin + a.getY() * cos;
return new Vector2d( ax, ay );
}
private void drawOnBoard( Graphics g, String str, int x, int y ) {
g.setFont( new Font( Font.MONOSPACED, Font.BOLD, ( int ) scale * 5 ) );
g.drawString( str, ( int ) ( ( centerX + x + stringBoardX ) * scale ) + offsetX, ( int ) ( ( centerY - y + stringBoardY ) * scale ) + offsetY );
}
@Override
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 );
if ( data != null ) {
int highestX = 40;
if ( !data.edges.isEmpty() ) {
Collection< Point > points = data.vertices;
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 ) {
Point p1 = segment.getStart();
Point p2 = segment.getEnd();
g.drawLine(
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX,
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY,
( int ) ( ( centerX + p2.getX() + highestX ) * scale ) + offsetX,
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY
);
}
for ( final Point point : points ) {
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 ) );
}
}
{
int count = 2;
Random random = new Random( hashCode() );
final int spacing = 25;
for ( final Polygon p : data.polygons ) {
final List< Point > points = p.getPoints();
final int[] x = new int[ points.size() ];
final int[] y = new int[ points.size() ];
final int[] xOffset = new int[ points.size() ];
final int[] yOffset = new int[ points.size() ];
final int[] filledX = new int[ points.size() ];
final int[] filledY = new int[ points.size() ];
for ( int i = 0; i < points.size(); ++i ) {
final Point point = points.get( i );
x[ i ] = ( int ) ( ( centerX + point.getX() ) * scale ) + offsetX;
y[ i ] = ( int ) ( ( centerY - point.getY() - 150 ) * scale ) + offsetY;
xOffset[ i ] = ( int ) ( ( centerX + point.getX() + count * spacing ) * scale ) + offsetX;
yOffset[ i ] = ( int ) ( ( centerY - point.getY() - 150 ) * scale ) + offsetY;
filledX[ i ] = ( int ) ( ( centerX + point.getX() ) * scale ) + offsetX;
filledY[ i ] = ( int ) ( ( centerY - point.getY() ) * scale ) + offsetY;
}
g.setColor( Color.BLACK );
g.drawPolygon( x, y, points.size() );
g.drawPolygon( xOffset, yOffset, points.size() );
g.setColor( new Color( random.nextInt( 0x1000000 ) ) );
g.fillPolygon( filledX, filledY, points.size() );
++count;
}
}
{
g.setColor( Color.RED );
for ( final Chain chain : data.chains ) {
final Point p1 = chain.getStart();
final Point p2 = chain.getEnd();
g.drawLine(
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX,
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY,
( int ) ( ( centerX + p2.getX() + highestX ) * scale ) + offsetX,
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY
);
}
}
{
g.setColor( Color.BLUE );
for ( final Chain chain : data.selectedChains ) {
final Point p1 = chain.getStart();
final Point p2 = chain.getEnd();
g.drawLine(
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX,
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY,
( int ) ( ( centerX + p2.getX() + highestX ) * scale ) + offsetX,
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY
);
}
}
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, "Optimal chain count: " + data.selectedChains.size(), 0, -20 );
}
java.awt.Point p = MouseInfo.getPointerInfo().getLocation();
java.awt.Point componentLocation = getLocationOnScreen();
p = new java.awt.Point( p.x - componentLocation.x, p.y - componentLocation.y );
g.setColor( Color.RED );
g.setFont( new Font( Font.MONOSPACED, Font.BOLD, 30 ) );
g.drawString( "X: " + ( ( p.x - offsetX ) / scale - centerX ), 10, 30 );
g.drawString( "Y: " + ( - ( ( p.y - offsetY ) / scale - centerY ) ), 10, 60 );
}
private static class PlaneData {
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 >();
}
}

View File

@@ -0,0 +1,16 @@
# Test 1
This test requires a directory called `polygons` in the current working directory,
filled with polygon files that follow the naming convention: `<string>,<int>,<int>`.
The polygon file format contains an arbitrary number of 2d polygons, with each polygon
following the given format:
```
<vertex-count>
<vertex-x> <vertex-y>
...
```
The intial line of the vertex count are followed by an extra line for each
vertex, containing the x and y coordinates of that vertex.
This program should be ran via the command line with `java -jar`. It will tesselate all
the files it can find as fast as possible, then output the time results.

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-application-visualizer-test-7</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest7</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer-test-7</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.aaaaahhhhhhh.bananapuncher714.mesh.test.MeshingTest7</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,98 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.test;
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.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
/**
* Mesh speed test for polygons
*/
public class MeshingTest7 {
private static final File BASE = new File( System.getProperty( "user.dir" ) );
private static final File POLYGON_DIR = new File( BASE, "polygons" );
public static void main( String[] args ) {
if ( POLYGON_DIR.exists() && POLYGON_DIR.isDirectory() ) {
System.out.println( "Found " + POLYGON_DIR.list().length + " files" );
final long allStart = System.currentTimeMillis();
final AtomicInteger index = new AtomicInteger( 0 );
final Collection< File > files = Arrays.asList( POLYGON_DIR.listFiles() );
files.parallelStream().forEach( f -> {
final StringBuilder builder = new StringBuilder();
builder.append( "Meshing file: " + f + "\n" );
final long start = System.currentTimeMillis();
final List< Polygon > polygons = mesh( f, builder );
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
for ( Polygon poly : polygons ) {
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
}
mesh.meshify();
long time = System.currentTimeMillis() - start;
builder.append( "\tTook " + time + "ms\n" );
builder.append( "\tCompleted " + index.incrementAndGet() + "/" + files.size() );
System.out.println( builder.toString() );
} );
System.out.println( "Took a total of " + ( System.currentTimeMillis() - allStart ) + "ms" );
} else {
System.err.println( "No such directory exists: " + POLYGON_DIR );
}
}
private static List< Polygon > mesh( File file, final StringBuilder stringBuilder ) {
// First parse the file to get a list of all polygons
final List< Polygon > polys = new ArrayList< Polygon >();
try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
String line;
while ( ( line = reader.readLine() ) != null ) {
if ( !line.isEmpty() ) {
final int pointCount = Integer.parseInt( line );
List< Point > points = new ArrayList< Point >( pointCount );
int point = 0;
while ( point < pointCount && ( line = reader.readLine() ) != null ) {
if ( !line.isEmpty() ) {
String[] values2 = line.split( " " );
final double px = Double.parseDouble( values2[ 0 ] );
final double py = Double.parseDouble( values2[ 1 ] );
points.add( new Point( px, py ) );
++point;
}
}
polys.add( new Polygon( points ) ) ;
}
}
} catch ( FileNotFoundException e ) {
e.printStackTrace();
return null;
} catch ( IOException e ) {
e.printStackTrace();
return null;
}
return polys;
}
}

View File

@@ -0,0 +1,23 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-application</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-application-visualizer</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<modules>
<module>Test1</module>
<module>Test2</module>
<module>Test3</module>
<module>Test4</module>
<module>Test5</module>
<module>Test6</module>
<module>Test7</module>
</modules>
</project>

2
core/algorithm/README.md Normal file
View File

@@ -0,0 +1,2 @@
# MC-Mesh Core Algorithm
The fundamental standalone tesselation library

25
core/algorithm/pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;

View File

@@ -1,13 +1,13 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
import java.util.HashSet; import java.util.LinkedHashSet;
/** /**
* A set for easily checking if a set contains/does not contain a half-edge or its sym. * A set for easily checking if a set contains/does not contain a half-edge or its sym.
* *
* @author BananaPuncher714 * @author BananaPuncher714
*/ */
public class EdgeSet extends HashSet< HalfEdge > { public class EdgeSet extends LinkedHashSet< HalfEdge > {
/** /**
* *
*/ */

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
/** /**
* A half-edge class used to represent a DCEL(doubly connected edge list): https://en.wikipedia.org/wiki/Doubly_connected_edge_list * A half-edge class used to represent a DCEL(doubly connected edge list): https://en.wikipedia.org/wiki/Doubly_connected_edge_list

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
/** /**
* A 2d Cartesian coordinate * A 2d Cartesian coordinate

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
/** /**
* A line segment * A line segment

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
/** /**
* A basic 2d vector implementation. * A basic 2d vector implementation.
@@ -66,6 +66,17 @@ public class Vector2d extends Point {
return add( this, o ); return add( this, o );
} }
public Vector2d absolute() {
x = Math.abs( x );
y = Math.abs( y );
return this;
}
public Vector2d absoluteOf() {
return new Vector2d( Math.abs( x ), Math.abs( y ) );
}
public Vector2d subtract( double v ) { public Vector2d subtract( double v ) {
x -= v; x -= v;
y -= v; y -= v;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm;
import java.util.Iterator; import java.util.Iterator;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.region; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.region; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region;
/** /**
* A continuous portion in space that can be clearly defined as "inside" or "outside". * A continuous portion in space that can be clearly defined as "inside" or "outside".

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.region; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region;
/** /**
* A region rule describes how a region is modified, particularly when crossing a border * A region rule describes how a region is modified, particularly when crossing a border

View File

@@ -1,7 +1,7 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.CompositeRegionRule; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.CompositeRegionRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.RegionRule; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.RegionRule;
/** /**
* A simple winding number rule. * A simple winding number rule.

View File

@@ -1,6 +1,6 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple; package com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.Region; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.Region;
/** /**
* A region with a winding number. The interior-ness of * A region with a winding number. The interior-ness of

2
core/base/README.md Normal file
View File

@@ -0,0 +1,2 @@
# MC-Mesh Core Base
Contains some classes for constructing meshes from 3d data

34
core/base/pom.xml Normal file
View File

@@ -0,0 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,9 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.base;
import java.util.ArrayList;
import java.util.List;
public class Facet {
public Vector3d normal;
public List< Vector3d > points = new ArrayList< Vector3d >();
}

View File

@@ -1,11 +1,9 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.base;
import org.bukkit.util.Vector;
public class LineSegment { public class LineSegment {
public Vector point1, point2; public Vector3d point1, point2;
public LineSegment( Vector point1, Vector point2 ) { public LineSegment( Vector3d point1, Vector3d point2 ) {
if ( point1.getX() < point2.getX() ) { if ( point1.getX() < point2.getX() ) {
this.point1 = point1; this.point1 = point1;
this.point2 = point2; this.point2 = point2;
@@ -39,7 +37,7 @@ public class LineSegment {
return point1.distance( point2 ); return point1.distance( point2 );
} }
public Vector getVector() { public Vector3d getVector() {
return point2.clone().subtract( point1 ); return new Vector3d( point2 ).subtract( point1 );
} }
} }

View File

@@ -0,0 +1,19 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.base;
public class Matrix3d {
protected Vector3d[] rows = new Vector3d[ 3 ];
public Matrix3d( Vector3d col1, Vector3d col2, Vector3d col3 ) {
rows[ 0 ] = new Vector3d( col1.getX(), col2.getX(), col3.getX() );
rows[ 1 ] = new Vector3d( col1.getY(), col2.getY(), col3.getY() );
rows[ 2 ] = new Vector3d( col1.getZ(), col2.getZ(), col3.getZ() );
}
public Matrix3d transpose() {
return new Matrix3d(
rows[ 0 ],
rows[ 1 ],
rows[ 2 ]
);
}
}

View File

@@ -0,0 +1,28 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.base;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class MeshBuilder {
public List< Plane > planes = new ArrayList< Plane >();
public Plane addFacet( Facet facet ) {
final Optional< Plane > opt = planes.stream().filter( p -> p.matches( facet.normal, facet.points.get( 0 ) ) ).findAny();
if ( opt.isPresent() ) {
final Plane plane = opt.get();
plane.addShape( facet );
return plane;
}
Plane plane = new Plane();
plane.normal = facet.normal;
Optional< Vector3d > ref = facet.points.stream().filter( v -> v.lengthSquared() > 0.001 && Math.abs( new Vector3d( v ).normalize().dot( facet.normal ) ) < .999999 ).findAny();
if ( ref.isPresent() ) {
plane.point = ref.get();
}
plane.addShape( facet );
planes.add( plane );
return plane;
}
}

View File

@@ -1,20 +1,16 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh; package com.aaaaahhhhhhh.bananapuncher714.mesh.base;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.util.Vector; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import org.joml.Matrix3d; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import org.joml.Vector3d;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
public class Plane { public class Plane {
public Vector normal; public Vector3d normal;
public Vector point; public Vector3d point;
public double distance; public double distance;
private boolean set = false; private boolean set = false;
@@ -28,21 +24,17 @@ public class Plane {
final Matrix3d mat = getProjectionMatrix(); final Matrix3d mat = getProjectionMatrix();
List< Point > polygon = new ArrayList< Point >(); List< Point > polygon = new ArrayList< Point >();
for ( Vector p : facet.points ) { for ( Vector3d p : facet.points ) {
double t = point.clone().subtract( p ).dot( normal ); double t = new Vector3d( point ).subtract( p ).dot( normal );
Vector i = normal.clone().multiply( t ).add( p ); Vector3d r = new Vector3d( normal ).multiply( t ).add( p ).multiply( mat );
Vector3d v = new Vector3d( i.getX(), i.getY(), i.getZ() );
Vector3d r = v.mul( mat );
polygon.add( new Point( r.x(), r.y() ) ); polygon.add( new Point( r.getX(), r.getY() ) );
if ( !set ) { if ( !set ) {
distance = r.z(); distance = r.getZ();
set = true; set = true;
} else if ( Math.abs( r.z() - distance ) > 1e-7 ) { } else if ( Math.abs( r.getZ() - distance ) > 1e-7 ) {
throw new IllegalStateException( "Bad point in facet!" ); throw new IllegalStateException( "Bad point in facet!" );
} }
} }
@@ -50,12 +42,12 @@ public class Plane {
polygons.add( new Polygon( polygon ) ); polygons.add( new Polygon( polygon ) );
} }
public Vector convert( final Point p ) { public Vector3d convert( final Point p ) {
final Vector3d plane = new Vector3d( p.getX(), p.getY(), distance ); final Vector3d plane = new Vector3d( p.getX(), p.getY(), distance );
final Vector3d res = plane.mul( getInverseProjectionMatrix() ); final Vector3d res = plane.multiply( getInverseProjectionMatrix() );
return new Vector( res.x(), res.y(), res.z() ); return res;
} }
public Facet convert( final Polygon polygon ) { public Facet convert( final Polygon polygon ) {
@@ -73,14 +65,13 @@ public class Plane {
return polygons.parallelStream().map( this::convert ).collect( Collectors.toSet() ); return polygons.parallelStream().map( this::convert ).collect( Collectors.toSet() );
} }
public boolean matches( Vector normal, Vector point ) { public boolean matches( Vector3d normal, Vector3d point ) {
return Math.abs( this.normal.dot( normal ) ) > 0.99 && Math.abs( this.point.clone().subtract( point ).dot( normal ) ) < 0.01; return Math.abs( this.normal.dot( normal ) ) > 0.999 && Math.abs( new Vector3d( this.point ).subtract( point ).dot( normal ) ) < 0.00001;
} }
private Matrix3d getProjectionMatrix() { private Matrix3d getProjectionMatrix() {
if ( mat == null ) { if ( mat == null ) {
final Vector basis1 = normal.clone().multiply( point.clone().multiply( -1 ).dot( normal ) ).add( point ).normalize(); final Vector3d b1 = new Vector3d( normal ).multiply( new Vector3d( point ).multiply( -1 ).dot( normal ) ).add( point ).normalize();
final Vector3d b1 = new Vector3d( basis1.getX(), basis1.getY(), basis1.getZ() );
final Vector3d b3 = new Vector3d( normal.getX(), normal.getY(), normal.getZ() ); final Vector3d b3 = new Vector3d( normal.getX(), normal.getY(), normal.getZ() );
final Vector3d b2 = new Vector3d( b1 ).cross( b3 ).normalize(); final Vector3d b2 = new Vector3d( b1 ).cross( b3 ).normalize();
mat = new Matrix3d( b1, b2, b3 ).transpose(); mat = new Matrix3d( b1, b2, b3 ).transpose();

View File

@@ -0,0 +1,156 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.base;
public class Vector3d {
private double x, y, z;
public Vector3d( double x, double y, double z ) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3d( Vector3d copy ) {
this.x = copy.x;
this.y = copy.y;
this.z = copy.z;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public void setX( double x ) {
this.x = x;
}
public void setY( double y ) {
this.y = y;
}
public void setZ( double z ) {
this.z = z;
}
public double dot( Vector3d o ) {
return x * o.x + y * o.y + z * o.z;
}
public Vector3d cross( Vector3d o ) {
return new Vector3d(
y * o.z - o.y * z,
z * o.x - o.z * x,
x * o.y - o.x * y
);
}
public double length() {
return Math.sqrt( lengthSquared() );
}
public double lengthSquared() {
return dot( this );
}
public Vector3d normalize() {
double length = length();
x /= length;
y /= length;
z /= length;
return this;
}
public Vector3d multiply( Matrix3d mat ) {
return new Vector3d(
dot( mat.rows[ 0 ] ),
dot( mat.rows[ 1 ] ),
dot( mat.rows[ 2 ] )
);
}
public Vector3d multiply( double v ) {
x *= v;
y *= v;
z *= v;
return this;
}
public Vector3d add( double v ) {
x += v;
y += v;
z += v;
return this;
}
public Vector3d add( Vector3d o ) {
x += o.x;
y += o.y;
z += o.z;
return this;
}
public Vector3d subtract( Vector3d o ) {
x -= o.x;
y -= o.y;
z -= o.z;
return this;
}
public double distance( Vector3d o ) {
return new Vector3d( this ).subtract( o ).length();
}
public double distanceSquared( Vector3d o ) {
return new Vector3d( this ).subtract( o ).lengthSquared();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(x);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(z);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Vector3d other = (Vector3d) obj;
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
return false;
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
return false;
if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
return false;
return true;
}
@Override
public String toString() {
return "Vector3d{x=" + x + ",y=" + y + ",z=" + z + "}";
}
}

18
core/pom.xml Normal file
View File

@@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-master</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>mc-mesh-core</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<modules>
<module>algorithm</module>
<module>base</module>
</modules>
</project>

14
install.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
export REV="1.21.11"
export M2_DIRECTORY="$M2_REPOSITORY"
export BUILD_DIRECTORY="$ARTIFACT_DIRECTORY"
export JAVA_VERSION="21"
REPOSITORY_DIR=$(dirname "$0")
cd "$REPOSITORY_DIR"
git submodule update --init --recursive --remote
./.git-submodules/spigot-docker-build-tools/run.sh mvn clean package

View File

@@ -0,0 +1,3 @@
# MC-Mesh Environment Plugin
This plugin aims to provide a comprehensive physics enabled environment
in Minecraft using BulletJME and the MC-Mesh core algorithm.

View File

@@ -0,0 +1,225 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>mc-mesh-plugin</artifactId>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mc-mesh-plugin-environment</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.21.11-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>spigot-api</artifactId>
<groupId>org.spigotmc</groupId>
</exclusion>
<exclusion>
<artifactId>jline</artifactId>
<groupId>org.jline</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-iostreams</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>asm-commons</artifactId>
<groupId>org.ow2.asm</groupId>
</exclusion>
<exclusion>
<artifactId>lz4-java</artifactId>
<groupId>at.yawk.lz4</groupId>
</exclusion>
<exclusion>
<artifactId>azure-json</artifactId>
<groupId>com.azure</groupId>
</exclusion>
<exclusion>
<artifactId>oshi-core</artifactId>
<groupId>com.github.oshi</groupId>
</exclusion>
<exclusion>
<artifactId>msal4j</artifactId>
<groupId>com.microsoft.azure</groupId>
</exclusion>
<exclusion>
<artifactId>authlib</artifactId>
<groupId>com.mojang</groupId>
</exclusion>
<exclusion>
<artifactId>brigadier</artifactId>
<groupId>com.mojang</groupId>
</exclusion>
<exclusion>
<artifactId>datafixerupper</artifactId>
<groupId>com.mojang</groupId>
</exclusion>
<exclusion>
<artifactId>jtracy</artifactId>
<groupId>com.mojang</groupId>
</exclusion>
<exclusion>
<artifactId>logging</artifactId>
<groupId>com.mojang</groupId>
</exclusion>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
<exclusion>
<artifactId>netty-buffer</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-codec-base</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-codec-compression</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-codec-http</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-common</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-handler</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-resolver</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-classes-epoll</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-classes-kqueue</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-native-epoll</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-native-epoll</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-native-kqueue</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-native-kqueue</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>netty-transport-native-unix-common</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>fastutil</artifactId>
<groupId>it.unimi.dsi</groupId>
</exclusion>
<exclusion>
<artifactId>jna</artifactId>
<groupId>net.java.dev.jna</groupId>
</exclusion>
<exclusion>
<artifactId>jna-platform</artifactId>
<groupId>net.java.dev.jna</groupId>
</exclusion>
<exclusion>
<artifactId>jopt-simple</artifactId>
<groupId>net.sf.jopt-simple</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang3</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-api</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-core</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-slf4j2-impl</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>jspecify</artifactId>
<groupId>org.jspecify</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
<exclusion>
<artifactId>json-simple</artifactId>
<groupId>com.googlecode.json-simple</groupId>
</exclusion>
<exclusion>
<artifactId>sqlite-jdbc</artifactId>
<groupId>org.xerial</groupId>
</exclusion>
<exclusion>
<artifactId>mysql-connector-j</artifactId>
<groupId>com.mysql</groupId>
</exclusion>
<exclusion>
<artifactId>maven-resolver-provider</artifactId>
<groupId>org.apache.maven</groupId>
</exclusion>
<exclusion>
<artifactId>maven-resolver-connector-basic</artifactId>
<groupId>org.apache.maven.resolver</groupId>
</exclusion>
<exclusion>
<artifactId>maven-resolver-transport-http</artifactId>
<groupId>org.apache.maven.resolver</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,71 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-plugin</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>mc-mesh-plugin-environment</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.21.11-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.stephengold</groupId>
<artifactId>Minie</artifactId>
<version>9.0.3+mt</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.scijava</groupId>
<artifactId>native-lib-loader</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-algorithm</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
<artifactId>mc-mesh-core-base</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -8,7 +8,7 @@ import java.util.Set;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.permissions.Permission; import org.bukkit.permissions.Permission;
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.BukkitUtil; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.BukkitUtil;
public class CommandBase { public class CommandBase {
protected PluginCommand command; protected PluginCommand command;

View File

@@ -1,8 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutable; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor.CommandExecutable;
public class CommandOption { public class CommandOption {
protected CommandExecutable exe; protected CommandExecutable exe;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
public class SplitCommand { public class SplitCommand {
protected String[] input; protected String[] input;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -13,10 +13,10 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutable; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor.CommandExecutable;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidator; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidator;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidatorString; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidatorString;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender.SenderValidator; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender.SenderValidator;
/** /**
* A build and run command framework for automatic tab completions and easy branching. * A build and run command framework for automatic tab completions and easy branching.

View File

@@ -1,8 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.CommandParameters; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.CommandParameters;
public interface CommandExecutable { public interface CommandExecutable {
void execute( CommandSender sender, String[] args, CommandParameters params ); void execute( CommandSender sender, String[] args, CommandParameters params );

View File

@@ -1,8 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.CommandParameters; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.CommandParameters;
public class CommandExecutableMessage implements CommandExecutable { public class CommandExecutableMessage implements CommandExecutable {
protected String message; protected String message;

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author BananaPuncher714
*
*/
package com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor;

View File

@@ -3,4 +3,4 @@
* *
* @author BananaPuncher714 * @author BananaPuncher714
*/ */
package com.aaaaahhhhhhh.bananapuncher714.minietest.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;

View File

@@ -0,0 +1,39 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection;
import org.bukkit.command.CommandSender;
public class InputValidatorDouble implements InputValidator< Double > {
protected double min = Integer.MIN_VALUE;
protected double max = Integer.MAX_VALUE;
public InputValidatorDouble() {
}
public InputValidatorDouble( double min, double max ) {
this.min = min;
this.max = max;
}
@Override
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
return null;
}
@Override
public boolean isValid( CommandSender sender, String[] input, String[] args ) {
try {
double i = Double.valueOf( input[ 0 ] );
return i >= min && i <= max;
} catch ( Exception exception ) {
return false;
}
}
@Override
public Double get( CommandSender sender, String[] input ) {
return Double.parseDouble( input[ 0 ] );
}
}

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author BananaPuncher714
*
*/
package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author BananaPuncher714
*
*/
package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;

View File

@@ -0,0 +1,10 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
public interface EnvironmentHandler {
public void onMeshLoad( ChunkLocation location, ChunkMesh mesh );
public void onMeshUnload( ChunkLocation location, ChunkMesh mesh );
public void onMeshUpdate( ChunkLocation location, ChunkMesh mesh );
}

View File

@@ -0,0 +1,63 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.io.Serializable;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
public class Aabb implements Serializable {
private static final long serialVersionUID = 6518512405568765913L;
public final int minX;
public final int minY;
public final int minZ;
public final int maxX;
public final int maxY;
public final int maxZ;
public final int width;
public final int depth;
public final int height;
public Aabb( Vector min, Vector max ) {
this( min.getBlockX(), min.getBlockY(), min.getBlockZ(), max.getBlockX(), max.getBlockY(), max.getBlockZ() );
}
public Aabb( final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ ) {
this.minX = minX;
this.minY = minY;
this.minZ = minZ;
this.maxX = maxX;
this.maxY = maxY;
this.maxZ = maxZ;
this.width = maxX - minX;
this.depth = maxZ - minZ;
this.height = maxY - minY;
}
public Aabb( final BoundingBox box ) {
this.minX = ( int ) box.getMinX();
this.maxX = ( int ) box.getMaxX();
this.minY = ( int ) box.getMinY();
this.maxY = ( int ) box.getMaxY();
this.minZ = ( int ) box.getMinZ();
this.maxZ = ( int ) box.getMaxZ();
this.width = maxX - minX;
this.depth = maxZ - minZ;
this.height = maxY - minY;
}
public int getVolume() {
return width * depth * height;
}
public Vector getMinimumCorner() {
return new Vector( minX, minY, minZ );
}
public Vector getMaximumCorner() {
return new Vector( maxX, maxY, maxZ );
}
}

View File

@@ -0,0 +1,62 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import org.bukkit.util.Vector;
import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
import com.jme3.math.Vector3f;
public abstract class AbstractMesh {
// References to every point used by at least one planemesh
public TreeSet< VectorReference > pointReferences = new TreeSet< VectorReference >();
// Map of meshes to each plane
// TODO Allow for non axis-aligned planes
public Map< MinecraftPlane, PlaneMesh > planes = new TreeMap< MinecraftPlane, PlaneMesh >();
public abstract Vector getMinimumCorner();
public abstract Vector getMaximumCorner();
public abstract BlockDataInformation getBlockDataInformationFor( Vector position );
public abstract void setBlockDataInformationFor( BlockDataInformation information, Vector position );
public IndexedMesh toIndexedMesh() {
final Vector3f[] positionArray = new Vector3f[ pointReferences.size() ];
int vertexIndex = 0;
for ( final VectorReference ref : pointReferences ) {
final Vector vector = ref.vector;
positionArray[ vertexIndex ] = new Vector3f( ( float ) vector.getX(), ( float ) vector.getY(), ( float ) vector.getZ() );
ref.index = vertexIndex;
++vertexIndex;
}
final int totalTriangleCount = planes.values().stream().mapToInt( m -> m.completedPolygons.size() ).sum();
int triangleIndex = 0;
final int[] indexArray = new int[ totalTriangleCount * 3 ];
for ( final PlaneMesh mesh : planes.values() ) {
for ( final IndexedPolygon triangle : mesh.completedPolygons ) {
Collection< VectorReference > refs = triangle.getPoints();
if ( refs.size() != 3 ) {
throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" );
}
final int indexArrayStart = triangleIndex * 3;
Iterator< VectorReference > it = refs.iterator();
indexArray[ indexArrayStart ] = it.next().index;
indexArray[ indexArrayStart + 1 ] = it.next().index;
indexArray[ indexArrayStart + 2 ] = it.next().index;
++triangleIndex;
}
}
return new IndexedMesh( positionArray, indexArray );
}
}

View File

@@ -0,0 +1,25 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.BoundingBox;
public class BlockDataInformation {
// If the block is complex/simple/empty
public BlockDataType type;
// Hashcode of the current block's blockdata so we can check if it changed
public final int blockDataHash;
// The bounding boxes for each complex block, null if air or a cube
public BoundingBox[] boundingBoxes;
public BlockDataInformation( int hash ) {
blockDataHash = hash;
}
public BlockDataInformation( BlockData data ) {
blockDataHash = data.hashCode();
}
public boolean isBlockData( BlockData data ) {
return blockDataHash == data.hashCode();
}
}

View File

@@ -0,0 +1,5 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
public enum BlockDataType {
NONE, COMPLEX, SOLID
}

View File

@@ -0,0 +1,53 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.BitSet;
public class BlockDataTypeSet {
private static final int BLOCK_SIZE;
private static final BitSet[] SETS;
static {
final int length = BlockDataType.values().length;
BLOCK_SIZE = 32 - Integer.numberOfLeadingZeros( length );
SETS = new BitSet[ length ];
// Perhaps not the fastest, since it sets each bit in N time
for ( int i = 0; i < length; ++i ) {
final BitSet set = new BitSet();
for ( int j = 0; j < BLOCK_SIZE; ++j ) {
set.set( j, ( ( i >> j ) & 1 ) == 1 );
}
SETS[ i ] = set;
}
}
protected BitSet buffer;
public BlockDataTypeSet( final byte[] arr ) {
buffer = BitSet.valueOf( arr );
}
public BlockDataTypeSet( final int size ) {
buffer = new BitSet( size * BLOCK_SIZE );
}
public void set( final int index, final BlockDataType type ) {
final BitSet set = SETS[ type.ordinal() ];
for ( int i = 0; i < BLOCK_SIZE; ++i ) {
buffer.set( ( index * BLOCK_SIZE ) + i, set.get( i ) );
}
}
public BlockDataType get( final int index ) {
final int bufferIndex = index * BLOCK_SIZE;
int ord = 0;
for ( int i = buffer.nextSetBit( bufferIndex ); i >= bufferIndex && i < bufferIndex + BLOCK_SIZE; i = buffer.nextSetBit( i + 1 ) ) {
ord |= 1 << ( i - bufferIndex );
}
return BlockDataType.values()[ ord ];
}
public byte[] toByteArray() {
return buffer.toByteArray();
}
}

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -12,7 +12,7 @@ import org.bukkit.World;
* *
* @author BananaPuncher714 * @author BananaPuncher714
*/ */
public class ChunkLocation { public class ChunkLocation implements Comparable< ChunkLocation > {
private int x, z; private int x, z;
private String worldName; private String worldName;
private World world; private World world;
@@ -283,4 +283,16 @@ public class ChunkLocation {
public String toString() { public String toString() {
return "ChunkLocation{x:" + x + ",z:" + z + ",world:" + worldName + "}"; return "ChunkLocation{x:" + x + ",z:" + z + ",world:" + worldName + "}";
} }
@Override
public int compareTo( ChunkLocation o ) {
final int worldCompare = worldName.compareTo( o.worldName );
if ( worldCompare == 0 ) {
if ( x == o.x ) {
return Integer.compare( z, o.z );
}
return Integer.compare( x, o.x );
}
return worldCompare;
}
} }

View File

@@ -0,0 +1,323 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.MinecraftPlane.PlaneAxis;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.BinaryWriter;
import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
import com.jme3.math.Vector3f;
public class ChunkMesh extends AbstractMesh {
// TODO Public for now while I figure out how to organize the stuff properly
// Hashcode of the current block's blockdata so we can check if it changed
private int[] data;
// The bounding boxes for each complex block, null if air or a cube
private BoundingBox[][] boxes;
// Stores which blocks are complex/simple/empty
private BlockDataTypeSet blockTypes;
// Bounding box of this mesh
private Aabb box;
public ChunkMesh( BoundingBox box ) {
this.box = new Aabb( box );
final int volume = this.box.getVolume();
data = new int[ volume ];
boxes = new BoundingBox[ volume ][];
blockTypes = new BlockDataTypeSet( volume );
}
public ChunkMesh( Aabb box ) {
this.box = box;
final int volume = this.box.getVolume();
data = new int[ volume ];
boxes = new BoundingBox[ volume ][];
blockTypes = new BlockDataTypeSet( volume );
}
public void setType( final int index, final BlockDataType type ) {
blockTypes.set( index, type );
}
public BlockDataType getType( final int index ) {
return blockTypes.get( index );
}
public void setData( final int index, final BlockData data ) {
this.data[ index ] = data.getAsString().hashCode();
}
public void setBoxes( final int index, final BoundingBox[] boxes ) {
this.boxes[ index ] = boxes;
}
public boolean isBlockAt( final int index, final BlockData data ) {
return blockTypes.get( index ) == BlockDataType.COMPLEX && this.data[ index ] == data.getAsString().hashCode();
}
public BoundingBox[] getBoxesAt( final int index ) {
return boxes[ index ];
}
public PlaneMesh getOrAdd( final MinecraftPlane plane ) {
PlaneMesh results = planes.get( plane );
if ( results == null ) {
results = new PlaneMesh();
planes.put( plane, results );
}
return results;
}
@Override
public Vector getMinimumCorner() {
return box.getMinimumCorner();
}
@Override
public Vector getMaximumCorner() {
return box.getMaximumCorner();
}
@Override
public BlockDataInformation getBlockDataInformationFor( Vector position ) {
final int index = position.getBlockX() + ( position.getBlockZ() << 4 ) + ( position.getBlockY() << 8 );
BlockDataInformation information = new BlockDataInformation( data[ index ] );
information.type = getType( index );
information.boundingBoxes = getBoxesAt( index );
return information;
}
@Override
public void setBlockDataInformationFor( BlockDataInformation information, Vector position ) {
final int index = position.getBlockX() + ( position.getBlockZ() << 4 ) + ( position.getBlockY() << 8 );
data[ index ] = information.blockDataHash;
setType( index, information.type );
setBoxes( index, information.boundingBoxes );
}
@Override
public IndexedMesh toIndexedMesh() {
final Vector3f[] positionArray = new Vector3f[ pointReferences.size() ];
int vertexIndex = 0;
for ( final VectorReference ref : pointReferences ) {
final Vector vector = ref.vector;
positionArray[ vertexIndex ] = new Vector3f( ( float ) vector.getX(), ( float ) vector.getY(), ( float ) vector.getZ() );
ref.index = vertexIndex;
++vertexIndex;
}
final int totalTriangleCount = planes.values().stream().mapToInt( m -> m.completedPolygons.size() ).sum();
int triangleIndex = 0;
final int[] indexArray = new int[ totalTriangleCount * 3 ];
for ( final PlaneMesh mesh : planes.values() ) {
for ( final IndexedPolygon triangle : mesh.completedPolygons ) {
Collection< VectorReference > refs = triangle.getPoints();
if ( refs.size() != 3 ) {
throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" );
}
final int indexArrayStart = triangleIndex * 3;
Iterator< VectorReference > it = refs.iterator();
indexArray[ indexArrayStart ] = it.next().index;
indexArray[ indexArrayStart + 1 ] = it.next().index;
indexArray[ indexArrayStart + 2 ] = it.next().index;
++triangleIndex;
}
}
return new IndexedMesh( positionArray, indexArray );
}
public void writeTo( final BinaryWriter writer ) {
// Gather all vectors and map them to indices
// Write the bounding box
writer.write( box.minX );
writer.write( box.minY );
writer.write( box.minZ );
writer.write( box.maxX );
writer.write( box.maxY );
writer.write( box.maxZ );
// Write our data blocks
for ( final int hash : data ) {
writer.write( hash );
}
// Write our bounding boxes
for ( final BoundingBox[] boxArr : boxes ) {
// Write how many boxes
if ( boxArr == null ) {
writer.write( ( int ) 0 );
} else {
writer.write( boxArr.length );
for ( final BoundingBox box : boxArr ) {
writer.write( box.getMinX() );
writer.write( box.getMinY() );
writer.write( box.getMinZ() );
writer.write( box.getMaxX() );
writer.write( box.getMaxY() );
writer.write( box.getMaxZ() );
}
}
}
// Write our block types
final byte[] blockTypeBuf = blockTypes.toByteArray();
writer.write( blockTypeBuf.length );
writer.write( blockTypeBuf );
// Write our point references
writer.write( pointReferences.size() );
for ( final VectorReference ref : pointReferences ) {
writer.write( ref.vector.getX() );
writer.write( ref.vector.getY() );
writer.write( ref.vector.getZ() );
writer.write( ref.index );
writer.write( ref.referenceCount );
}
// Write our planes
writer.write( planes.size() );
for ( final Entry< MinecraftPlane, PlaneMesh > entry : planes.entrySet() ) {
final MinecraftPlane plane = entry.getKey();
writer.write( plane.normal.ordinal() );
writer.write( plane.offset );
final PlaneMesh mesh = entry.getValue();
// Write each region
writer.write( mesh.generatedRegions.size() );
for ( final Polygon poly : mesh.generatedRegions ) {
writer.write( poly.getPoints().size() );
for ( final Point p : poly.getPoints() ) {
writer.write( p.getX() );
writer.write( p.getY() );
}
}
// Write each triangle
writer.write( mesh.completedPolygons.size() );
for ( final IndexedPolygon poly : mesh.completedPolygons ) {
writer.write( poly.getPointCount() );
for ( final VectorReference ref : poly.getPoints() ) {
writer.write( ref.index );
}
}
}
}
public static ChunkMesh readFrom( final ByteBuffer buffer ) {
final Aabb box = new Aabb( buffer.getInt(), buffer.getInt(), buffer.getInt(), buffer.getInt(), buffer.getInt(), buffer.getInt() );
final ChunkMesh mesh = new ChunkMesh( box );
final int size = box.getVolume();
buffer.asIntBuffer().get( mesh.data );
buffer.position( buffer.position() + ( mesh.data.length << 2 ) );
// Read our boxes
for ( int i = 0; i < size; ++i ) {
final int boxCount = buffer.getInt();
if ( boxCount > 0 ) {
final BoundingBox[] boxes = new BoundingBox[ boxCount ];
for ( int j = 0; j < boxCount; ++j ) {
boxes[ j ] = new BoundingBox( buffer.getDouble(), buffer.getDouble(), buffer.getDouble(), buffer.getDouble(), buffer.getDouble(), buffer.getDouble() );
}
mesh.boxes[ i ] = boxes;
}
}
// Read the block types
final int blockTypeBufSize = buffer.getInt();
final byte[] bitSet = new byte[ blockTypeBufSize ];
buffer.get( bitSet );
mesh.blockTypes = new BlockDataTypeSet( bitSet );
// Read the plane references
final int pointCount = buffer.getInt();
final VectorReference[] references = new VectorReference[ pointCount ];
for ( int i = 0; i < pointCount; ++i ) {
final VectorReference reference = new VectorReference( new Vector( buffer.getDouble(), buffer.getDouble(), buffer.getDouble() ) );
reference.index = buffer.getInt();
reference.referenceCount = buffer.getInt();
references[ reference.index ] = reference;
mesh.pointReferences.add( reference );
}
// Get the planes
final int planeCount = buffer.getInt();
for ( int i = 0; i < planeCount; ++i ) {
final MinecraftPlane plane = new MinecraftPlane( PlaneAxis.values()[ buffer.getInt() ], buffer.getDouble() );
final PlaneMesh planeMesh = new PlaneMesh();
planeMesh.generatedRegions = new ArrayDeque< Polygon >();
planeMesh.completedPolygons = new ArrayDeque< IndexedTriangle >();
final int regionCount = buffer.getInt();
for ( int j = 0; j < regionCount; ++j ) {
final int vertexCount = buffer.getInt();
final List< Point > points = new ArrayList< Point >();
for ( int k = 0; k < vertexCount; ++k ) {
points.add( new Point( buffer.getDouble(), buffer.getDouble() ) );
}
planeMesh.generatedRegions.add( new Polygon( points ) );
}
final int triangleCount = buffer.getInt();
for ( int j = 0; j < triangleCount; ++j ) {
final int vertexCount = buffer.getInt();
final IndexedTriangle triangle = new IndexedTriangle();
for ( int k = 0; k < vertexCount; ++k ) {
switch ( k ) {
case 0:
triangle.setPoint1( references[ buffer.getInt() ] );
break;
case 1:
triangle.setPoint2( references[ buffer.getInt() ] );
break;
case 2:
triangle.setPoint3( references[ buffer.getInt() ] );
break;
default:
// Discard
buffer.getInt();
}
}
planeMesh.completedPolygons.add( triangle );
}
mesh.planes.put( plane, planeMesh );
}
return mesh;
}
}

View File

@@ -0,0 +1,19 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class IndexedNGon implements IndexedPolygon {
List< VectorReference > points = new ArrayList< VectorReference >();
@Override
public Collection< VectorReference > getPoints() {
return points;
}
@Override
public int getPointCount() {
return points.size();
}
}

View File

@@ -0,0 +1,11 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
/*
* Represents a polygon with associated vector references
*/
public abstract interface IndexedPolygon {
public Collection< VectorReference > getPoints();
public int getPointCount();
}

View File

@@ -0,0 +1,44 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
import java.util.List;
public class IndexedTriangle implements IndexedPolygon {
private VectorReference p1;
private VectorReference p2;
private VectorReference p3;
public VectorReference getPoint1() {
return p1;
}
public VectorReference getPoint2() {
return p2;
}
public VectorReference getPoint3() {
return p3;
}
public void setPoint1( VectorReference p1 ) {
this.p1 = p1;
}
public void setPoint2( VectorReference p2 ) {
this.p2 = p2;
}
public void setPoint3( VectorReference p3 ) {
this.p3 = p3;
}
@Override
public Collection< VectorReference > getPoints() {
return List.of( p1, p2, p3 );
}
@Override
public int getPointCount() {
return 3;
}
}

Some files were not shown because too many files have changed in this diff Show More