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
197 lines
8.4 KiB
Java
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;
|
|
}
|
|
}
|