Files
mc-mesh/src/main/java/com/aaaaahhhhhhh/bananapuncher714/tess4j/Util.java
BananaPuncher714 d16041f977 Improve tessellation algorithm
Added new mesh class
Rewrite mesh algorithms to be less error prone
Make code more concise
Tried to add some documentation
Added half edge set
2025-05-04 00:04:22 -04:00

197 lines
8.4 KiB
Java

package com.aaaaahhhhhhh.bananapuncher714.tess4j;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import org.joml.Math;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
public class Util {
protected static String toString( Object obj ) {
StringBuilder builder = new StringBuilder();
builder.append( obj.getClass().getSimpleName() );
builder.append( '{' );
List< Field > fields = new ArrayList< Field >();
fields.addAll( Arrays.asList( obj.getClass().getDeclaredFields() ) );
fields.addAll( Arrays.asList( obj.getClass().getFields() ) );
for ( Iterator< Field > it = fields.iterator(); it.hasNext(); builder.append( "," ) ) {
Field field = it.next();
builder.append( field.getName() );
builder.append( '=' );
try {
builder.append( field.get( obj ) );
} catch ( IllegalArgumentException | IllegalAccessException e ) {
builder.append( "?" );
}
}
builder.append( '}' );
return builder.toString();
}
public static Optional< Point > intersection( final VertexOld x1, final VertexOld x2, final VertexOld x3, final VertexOld x4 ) {
Point point = null;
final Vector2dOld p = x1.toVector();
final Vector2dOld r = x2.subtract( x1 );
final Vector2dOld q = x3.toVector();
final Vector2dOld s = x4.subtract( x3 );
final Vector2dOld qp = q.subtract( p );
final double qpr = qp.cross( r );
final double rs = r.cross( s );
// Are the two lines parallel
if ( rs == 0 ) {
final Vector2dOld u = x2.toVector();
final Vector2dOld v = x4.toVector();
// For normalizing against pr
final double rr = r.dot( r );
// t0 and t1 represent the distance of the second edge endpoints relative to the first edge normalized by r
// t0 = ( ( q - p ) . r ) / rr;
double t0 = qp.dot( r ) / rr;
// t1 = ( ( q + s - p ) . r ) / rr
double t1 = v.subtract( p ).dot( r ) / rr;
// If the vectors are pointing in the opposite directions, then swap t0 and t1
final boolean inverted = s.dot( r ) < 0;
if ( inverted ) {
double temp = t0;
t0 = t1;
t1 = temp;
}
if ( qpr == 0 ) {
if ( t0 < 1 & t1 > 0 ) {
final double midt = Math.max( t0, 0 ) + Math.min( t1, 1 ) / 2.0;
final Vector2dOld midpoint = r.multiply( midt ).add( p );
point = midpoint.toPoint();
} else {
final Vector2dOld pu = t0 > 1 ? u : p;
// Same as the first edge but the second edge may be inverted
final Vector2dOld qv = ( inverted ^ t0 > 1 ) ? q : v;
final Vector2dOld midpoint = pu.add( qv ).divide( 2.0 );
point = midpoint.toPoint();
}
}
} else {
// Calculate t and u
final double t = qp.cross( s ) / rs;
final double u = qpr / rs;
// Do the line segments intersect
if ( t >= 0 && t <= 1 && u >= 0 && u <= 1 ) {
// Calculate the point of intersection
final Vector2dOld intersection = r.multiply( t ).add( p );
point = intersection.toPoint();
}
}
return Optional.ofNullable( point );
}
// https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
// Vector based closest intersection method
public static Point closestPoint( final VertexOld x1, final VertexOld x2, final VertexOld x3, final VertexOld x4 ) {
Point point = new Point( 0, 0 );
final Vector2dOld p = x1.toVector();
final Vector2dOld r = x2.subtract( x1 );
final Vector2dOld q = x3.toVector();
final Vector2dOld s = x4.subtract( x3 );
final Vector2dOld qp = q.subtract( p );
final double qpr = qp.cross( r );
final double rs = r.cross( s );
// Are the two lines parallel
if ( rs == 0 ) {
final Vector2dOld u = x2.toVector();
final Vector2dOld v = x4.toVector();
// For normalizing against pr
final double rr = r.dot( r );
// t0 and t1 represent the distance of the second edge endpoints relative to the first edge normalized by r
// t0 = ( ( q - p ) . r ) / rr;
double t0 = qp.dot( r ) / rr;
// t1 = ( ( q + s - p ) . r ) / rr
double t1 = v.subtract( p ).dot( r ) / rr;
// If the vectors are pointing in the opposite directions, then swap t0 and t1
final boolean inverted = s.dot( r ) < 0;
if ( inverted ) {
double temp = t0;
t0 = t1;
t1 = temp;
}
// Do the lines overlap
if ( t0 < 1 && t1 > 0 ) {
// The midpoint is an arbitrary point that just happens to look good as an intersection
// Find the midpoint between the overlapping region
final double midt = Math.max( t0, 0 ) + Math.min( t1, 1 ) / 2.0;
// If colinear
if ( qpr == 0 ) {
// Do not need to calculate the distance between the two parallel lines since it is 0
final Vector2dOld midpoint = r.multiply( midt ).add( p );
point.setX( midpoint.x );
point.setY( midpoint.y );
} else {
// Calculate the midpoint along pr
final Vector2dOld midp = r.multiply( midt ).add( p );
// Calculate the perpendicular distance between both lines
final Vector2dOld perp = r.perpendicular();
final Vector2dOld z = perp.multiply( qp.dot( perp ) / rr );
// Sum the components
final Vector2dOld midpoint = midp.add( z.divide( 2.0 ) );
point.setX( midpoint.x );
point.setY( midpoint.y );
}
} else {
// The lines aren't really anywhere close to each other, so just find the midpoint between the 2 closest points
// If t0 > 1, then the second edge must lie to the right of the first edge
final Vector2dOld pu = t0 > 1 ? u : p;
// Same as the first edge but the second edge may be inverted
final Vector2dOld qv = ( inverted ^ t0 > 1 ) ? q : v;
final Vector2dOld midpoint = pu.add( qv ).divide( 2.0 );
point.setX( midpoint.x );
point.setY( midpoint.y );
}
} else {
// Calculate t and u
final double t = qp.cross( s ) / rs;
final double u = qpr / rs;
// Do the line segments intersect
if ( t >= 0 && t <= 1 && u >= 0 && u <= 1 ) {
// Calculate the point of intersection
final Vector2dOld intersection = r.multiply( t ).add( p );
point.setX( intersection.x );
point.setY( intersection.y );
} else {
// No intersection, so calculate the closest point between the two segments
// We have t and u, which we can use to find the closest endpoints
final double nearT = Math.max( Math.min( t, 1 ), 0 );
final double nearU = Math.max( Math.min( u, 1 ), 0 );
final Vector2dOld nearP = r.multiply( nearT ).add( p );
final Vector2dOld nearQ = s.multiply( nearU ).add( q );
point.setX( ( nearP.x + nearQ.x ) / 2.0 );
point.setY( ( nearP.y + nearQ.y ) / 2.0 );
}
}
return point;
}
}