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; } }