Fix inconsistencies
Use linked hash set for reproducibility when required Split chain generation into three smaller methods Fixed error when certain chains skip certain vertices, specifically after splitting a partition Hide internal classes Add conversion to external classes when returning data Update the polygon viewer Update chain intersections in parallel Sort edges cleaner Resolve some TODOs
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.mesh;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Chain {
|
||||||
|
protected List< Point > points = new ArrayList< Point >();
|
||||||
|
protected List< Chain > intersections = new ArrayList< Chain >();
|
||||||
|
|
||||||
|
public Point getStart() {
|
||||||
|
return points.get( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getEnd() {
|
||||||
|
return points.get( points.size() - 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List< Point > getPoints() {
|
||||||
|
return Collections.unmodifiableList( points );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List< Chain > getIntersections() {
|
||||||
|
return Collections.unmodifiableList( intersections );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -18,6 +19,7 @@ import java.util.Queue;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ import com.aaaaahhhhhhh.bananapuncher714.mesh.region.RegionRule;
|
|||||||
* The time complexity for the entire algorithm should be roughly O(n^2logn).
|
* The time complexity for the entire algorithm should be roughly O(n^2logn).
|
||||||
*
|
*
|
||||||
* TODO Remove guaranteed checks or add some compile time thing to remove
|
* TODO Remove guaranteed checks or add some compile time thing to remove
|
||||||
|
* TODO Update this description
|
||||||
*
|
*
|
||||||
* @author BananaPuncher714
|
* @author BananaPuncher714
|
||||||
*/
|
*/
|
||||||
@@ -86,8 +89,7 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
protected MeshState state = MeshState.TRIANGULATION_READY;
|
protected MeshState state = MeshState.TRIANGULATION_READY;
|
||||||
|
|
||||||
// TODO Remove
|
protected Collection< MeshEventHandler > handlers = new LinkedHashSet< MeshEventHandler >();
|
||||||
public Collection< Chain > chains;
|
|
||||||
|
|
||||||
public Mesh( final Supplier< T > defaultRegionSupplier ) {
|
public Mesh( final Supplier< T > defaultRegionSupplier ) {
|
||||||
this.defaultRegionSupplier = defaultRegionSupplier;
|
this.defaultRegionSupplier = defaultRegionSupplier;
|
||||||
@@ -120,11 +122,36 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection< Vertex > getVertices() {
|
public boolean addHandler( final MeshEventHandler handler ) {
|
||||||
return vertices;
|
return handlers.add( handler );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRuleSize() {
|
public boolean removeHandler( final MeshEventHandler handler ) {
|
||||||
|
return handlers.remove( handler );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection< MeshEventHandler > getHandlers() {
|
||||||
|
return Collections.unmodifiableCollection( handlers );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set< Point > getVertices() {
|
||||||
|
return vertices.parallelStream().map( v -> { return new Point( v.getPosition() ); } ).collect( Collectors.toSet() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set< Segment > getEdges() {
|
||||||
|
final EdgeSet set = new EdgeSet();
|
||||||
|
set.addAll( rules.keySet() );
|
||||||
|
|
||||||
|
final Map< Vertex, Point > pointMap = vertices.parallelStream().collect( Collectors.toMap( Function.identity(), v -> new Point( v.getPosition() ) ) );
|
||||||
|
|
||||||
|
return set.parallelStream().map( e -> new Segment( pointMap.get( e.getOrigin() ), pointMap.get( e.getDest() ) ) ).collect( Collectors.toSet() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVertexCount() {
|
||||||
|
return vertices.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEdgeCount() {
|
||||||
return rules.size();
|
return rules.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,6 +791,7 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
// Sort the edges around this vertex.
|
// Sort the edges around this vertex.
|
||||||
private static List< HalfEdge > sort( Vertex vertex ) {
|
private static List< HalfEdge > sort( Vertex vertex ) {
|
||||||
|
final Vector2d UP = new Vector2d( 0, 1 );
|
||||||
final List< HalfEdge > edges = new ArrayList< HalfEdge >();
|
final List< HalfEdge > edges = new ArrayList< HalfEdge >();
|
||||||
|
|
||||||
for ( final HalfEdge edge : vertex ) {
|
for ( final HalfEdge edge : vertex ) {
|
||||||
@@ -773,23 +801,22 @@ public class Mesh< T extends Region > {
|
|||||||
edges.add( edge );
|
edges.add( edge );
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Can really just figure this out based on the absolute angle?
|
|
||||||
// relative to the (0, 1) vector...
|
|
||||||
// Sort the edges in a counter clockwise direction,
|
// Sort the edges in a counter clockwise direction,
|
||||||
// where 11:59 is the least, and 12:00 is the greatest
|
// where 11:59 is the least, and 12:00 is the greatest
|
||||||
Collections.sort( edges, ( e1, e2 ) -> {
|
Collections.sort( edges, ( e1, e2 ) -> {
|
||||||
// This assumes that no edge has length of 0
|
// This assumes that no edge has length of 0
|
||||||
final boolean e1p = isPositive( e1 );
|
final Vector2d vec1 = e1.toVector2d().normalize();
|
||||||
final boolean e2p = isPositive( e2 );
|
final Vector2d vec2 = e2.toVector2d().normalize();
|
||||||
|
double cross1 = vec1.angle( UP );
|
||||||
if ( e1p ^ e2p ) {
|
if ( cross1 < 0 ) {
|
||||||
return e1p ? 1 : -1;
|
cross1 += 10;
|
||||||
} else if ( e1.getDest() == e2.getDest() ) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
final double cross = e2.toVector2d().cross( e1.toVector2d() );
|
|
||||||
return Double.compare( cross, 0 );
|
|
||||||
}
|
}
|
||||||
|
double cross2 = vec2.angle( UP );
|
||||||
|
if ( cross2 < 0 ) {
|
||||||
|
cross2 += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Double.compare( cross2, cross1 );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Only need to re-organize the edges if there are 3 or more
|
// Only need to re-organize the edges if there are 3 or more
|
||||||
@@ -891,9 +918,7 @@ public class Mesh< T extends Region > {
|
|||||||
return toRemove;
|
return toRemove;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Provide triangles
|
public Collection< Polygon > mesh() {
|
||||||
// and preferrably a simple polygon
|
|
||||||
public Collection< EdgePolygon > mesh() {
|
|
||||||
if ( state != MeshState.TRIANGULATION_READY ) {
|
if ( state != MeshState.TRIANGULATION_READY ) {
|
||||||
throw new IllegalStateException( "Mesh has not been split into regions!" );
|
throw new IllegalStateException( "Mesh has not been split into regions!" );
|
||||||
}
|
}
|
||||||
@@ -904,7 +929,7 @@ public class Mesh< T extends Region > {
|
|||||||
final Map< Vertex, Vertex > newVertices = new HashMap< Vertex, Vertex >();
|
final Map< Vertex, Vertex > newVertices = new HashMap< Vertex, Vertex >();
|
||||||
|
|
||||||
// Keep track of all newly added interior edges
|
// Keep track of all newly added interior edges
|
||||||
final Collection< HalfEdge > edges = new HashSet< HalfEdge >();
|
final Collection< HalfEdge > edges = new LinkedHashSet< HalfEdge >();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We now want to create a completely separate PSLG so that we don't modify
|
* We now want to create a completely separate PSLG so that we don't modify
|
||||||
@@ -954,18 +979,60 @@ public class Mesh< T extends Region > {
|
|||||||
// Sort each vertex so that the edge they are pointing to is the least edge
|
// Sort each vertex so that the edge they are pointing to is the least edge
|
||||||
vertices.parallelStream().forEach( v -> sort( v ) );
|
vertices.parallelStream().forEach( v -> sort( v ) );
|
||||||
|
|
||||||
final Collection< Chain > chains = reduceCollinear2( vertices, edges );
|
final Collection< Link > allChains = findChains( vertices, edges );
|
||||||
this.chains = new ArrayDeque< Chain >();
|
final Collection< Link > chains = maximizeChains( allChains );
|
||||||
for ( Chain chain : chains ) {
|
if ( !handlers.isEmpty() ) {
|
||||||
List< HalfEdge > newEdges = new ArrayList< HalfEdge >();
|
final Collection< Chain > newChains = new HashSet< Chain >();
|
||||||
for ( HalfEdge e : chain.links ) {
|
final Collection< Link > seen = new HashSet< Link >();
|
||||||
HalfEdge edge = new HalfEdge();
|
|
||||||
edge.getOrigin().setPosition( e.getOrigin().getPosition() );
|
for ( final Link link : allChains ) {
|
||||||
edge.getDest().setPosition( e.getDest().getPosition() );
|
if ( seen.add( link ) ) {
|
||||||
newEdges.add( edge );
|
Link head = link;
|
||||||
|
while ( head.previous != null ) {
|
||||||
|
head = head.previous;
|
||||||
}
|
}
|
||||||
this.chains.add( new Chain( newEdges ) );
|
|
||||||
|
final Chain chain = new Chain();
|
||||||
|
Link previous;
|
||||||
|
do {
|
||||||
|
chain.points.add( new Point( head.getOrigin().getPosition() ) );
|
||||||
|
seen.add( head );
|
||||||
|
previous = head;
|
||||||
|
} while ( ( head = head.next ) != null );
|
||||||
|
chain.points.add( new Point( previous.getMidpoint().getPosition() ) );
|
||||||
|
chain.points.add( new Point( previous.getDest().getPosition() ) );
|
||||||
|
newChains.add( chain );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.forEach( h -> h.onChainGenerationEvent( newChains ) );
|
||||||
|
|
||||||
|
final Collection< Link > selectedSeen = new HashSet< Link >();
|
||||||
|
final Collection< Chain > selectedChains = new HashSet< Chain >();
|
||||||
|
for ( final Link link : chains ) {
|
||||||
|
if ( selectedSeen.add( link ) ) {
|
||||||
|
Link head = link;
|
||||||
|
while ( chains.contains( head.previous ) ) {
|
||||||
|
head = head.previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Chain chain = new Chain();
|
||||||
|
Link previous;
|
||||||
|
do {
|
||||||
|
chain.points.add( new Point( head.getOrigin().getPosition() ) );
|
||||||
|
selectedSeen.add( head );
|
||||||
|
previous = head;
|
||||||
|
} while ( ( head = head.next ) != null && chains.contains( head ) );
|
||||||
|
chain.points.add( new Point( previous.getMidpoint().getPosition() ) );
|
||||||
|
chain.points.add( new Point( previous.getDest().getPosition() ) );
|
||||||
|
selectedChains.add( chain );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.forEach( h -> h.onPreChainMergeEvent( selectedChains ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeChains( chains, edges );
|
||||||
|
|
||||||
return partitionMonotone( vertices, edges ).parallelStream()
|
return partitionMonotone( vertices, edges ).parallelStream()
|
||||||
.map( Mesh::triangulate )
|
.map( Mesh::triangulate )
|
||||||
@@ -973,34 +1040,6 @@ public class Mesh< T extends Region > {
|
|||||||
.collect( Collectors.toSet() );
|
.collect( Collectors.toSet() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Make not static
|
|
||||||
public static class Chain {
|
|
||||||
List< HalfEdge > links;
|
|
||||||
Set< Chain > intersections = new HashSet< Chain >();
|
|
||||||
Chain previous;
|
|
||||||
Chain next;
|
|
||||||
|
|
||||||
Chain( final Collection< HalfEdge > links ) {
|
|
||||||
this.links = new ArrayList< HalfEdge >( links );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex getOrigin() {
|
|
||||||
return links.get( 0 ).getOrigin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex getMidpoint() {
|
|
||||||
return links.get( 1 ).getOrigin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex getDest() {
|
|
||||||
return links.get( 2 ).getOrigin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List< HalfEdge > getLinks() {
|
|
||||||
return links;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This algorithm revolves around first generating chains, then sorting which chains and chain links to keep.
|
* This algorithm revolves around first generating chains, then sorting which chains and chain links to keep.
|
||||||
*
|
*
|
||||||
@@ -1015,7 +1054,7 @@ public class Mesh< T extends Region > {
|
|||||||
*
|
*
|
||||||
* The complexity comes from analyzing which combinations of chain links provides the greatest reduction of vertices.
|
* The complexity comes from analyzing which combinations of chain links provides the greatest reduction of vertices.
|
||||||
*/
|
*/
|
||||||
private static Collection< Chain > reduceCollinear2( final TreeSet< Vertex > vertices, final Collection< HalfEdge > interior ) {
|
private static Collection< Link > findChains( final TreeSet< Vertex > vertices, final Collection< HalfEdge > interior ) {
|
||||||
final Vector2d CROSS = new Vector2d( 1, 0 );
|
final Vector2d CROSS = new Vector2d( 1, 0 );
|
||||||
// Set maximum and minimum cross values that won't occur naturally
|
// Set maximum and minimum cross values that won't occur naturally
|
||||||
final double MAX_CROSS = 1.1;
|
final double MAX_CROSS = 1.1;
|
||||||
@@ -1092,7 +1131,7 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
// Keep track of all chains that were formed in this current partition.
|
// Keep track of all chains that were formed in this current partition.
|
||||||
// For all new chains, see what previous chains it may intersect with
|
// For all new chains, see what previous chains it may intersect with
|
||||||
Collection< Chain > chains = new HashSet< Chain >();
|
Collection< Link > chains = new LinkedHashSet< Link >();
|
||||||
|
|
||||||
Partition( final HalfEdge lower, final HalfEdge upper ) {
|
Partition( final HalfEdge lower, final HalfEdge upper ) {
|
||||||
this.lower = lower;
|
this.lower = lower;
|
||||||
@@ -1133,7 +1172,7 @@ public class Mesh< T extends Region > {
|
|||||||
// and we don't really care about what comes after
|
// and we don't really care about what comes after
|
||||||
links.add( edge );
|
links.add( edge );
|
||||||
|
|
||||||
final Chain chain = new Chain( links );
|
final Link chain = new Link( links );
|
||||||
addChain( chain );
|
addChain( chain );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1174,7 +1213,7 @@ public class Mesh< T extends Region > {
|
|||||||
// and we don't really care about what comes after
|
// and we don't really care about what comes after
|
||||||
links.add( edge );
|
links.add( edge );
|
||||||
|
|
||||||
final Chain chain = new Chain( links );
|
final Link chain = new Link( links );
|
||||||
addChain( chain );
|
addChain( chain );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1263,7 +1302,7 @@ public class Mesh< T extends Region > {
|
|||||||
// and we don't really care about what comes after
|
// and we don't really care about what comes after
|
||||||
links.add( edge );
|
links.add( edge );
|
||||||
|
|
||||||
final Chain chain = new Chain( links );
|
final Link chain = new Link( links );
|
||||||
addChain( chain );
|
addChain( chain );
|
||||||
}
|
}
|
||||||
} else if ( lowerCross > region.lower ) {
|
} else if ( lowerCross > region.lower ) {
|
||||||
@@ -1302,7 +1341,7 @@ public class Mesh< T extends Region > {
|
|||||||
// and we don't really care about what comes after
|
// and we don't really care about what comes after
|
||||||
links.add( edge );
|
links.add( edge );
|
||||||
|
|
||||||
final Chain chain = new Chain( links );
|
final Link chain = new Link( links );
|
||||||
addChain( chain );
|
addChain( chain );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,30 +1399,34 @@ public class Mesh< T extends Region > {
|
|||||||
* Check all previous chains for intersections and stuff. This method
|
* Check all previous chains for intersections and stuff. This method
|
||||||
* is unfortunately polynomial time(O(n^2)) and there's not much we can do about it.
|
* is unfortunately polynomial time(O(n^2)) and there's not much we can do about it.
|
||||||
*
|
*
|
||||||
* Maybe parallelize the intersection checking though? We'd need to ensure that the
|
|
||||||
* intersection collection for each chain is synchronized, but otherwise entirely possible.
|
|
||||||
*
|
|
||||||
* TODO Good idea, now someone needs to implement that.
|
|
||||||
*
|
|
||||||
* Also, just because the origin or destination may be the midpoint of another chain
|
* Also, just because the origin or destination may be the midpoint of another chain
|
||||||
* does not necessarily mean they coincide with each other... such as if the origin
|
* does not necessarily mean they coincide with each other... such as if the origin
|
||||||
* or endpoint are connected to the midpoint for one chain, but not the other
|
* or endpoint are connected to the midpoint for one chain, but not the other
|
||||||
*/
|
*/
|
||||||
void addChain( final Chain chain ) {
|
void addChain( final Link chain ) {
|
||||||
final Vertex chainOrigin = chain.getOrigin();
|
final Vertex chainOrigin = chain.getOrigin();
|
||||||
final Vertex chainMidpoint = chain.getMidpoint();
|
final Vertex chainMidpoint = chain.getMidpoint();
|
||||||
final Vertex chainDestination = chain.getDest();
|
final Vertex chainDestination = chain.getDest();
|
||||||
|
|
||||||
for ( final Chain other : chains ) {
|
for ( final Link other : chains ) {
|
||||||
if ( other.getOrigin() == chainOrigin && other.getDest() == chainDestination ) {
|
if ( other.getOrigin() == chainOrigin && other.getDest() == chainDestination ) {
|
||||||
// Already added this chain, so break out early
|
// Already added this chain, so break out early
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Synchronize the intersections for this chain so that we can check each
|
||||||
|
// other chain for intersection in parallel. The order of the intersections
|
||||||
|
// doesn't affect the reproducibility either, so it's fine.
|
||||||
|
final Collection< Link > intersections = Collections.synchronizedCollection( chain.intersections );
|
||||||
|
|
||||||
|
final HalfEdge firstEdge = chain.links.get( 0 );
|
||||||
|
final HalfEdge secondEdge = chain.links.get( 1 );
|
||||||
|
final Vector2d secondEdgeVec = secondEdge.toVector2d();
|
||||||
|
|
||||||
final Vector2d p = chainOrigin.getPosition();
|
final Vector2d p = chainOrigin.getPosition();
|
||||||
final Vector2d r = chainDestination.getPosition().subtracted( p );
|
final Vector2d r = chainDestination.getPosition().subtracted( p );
|
||||||
for ( final Chain other : chains ) {
|
chains.parallelStream().forEach( other -> {
|
||||||
if ( other.getMidpoint() == chainOrigin && other.getDest() == chainMidpoint ) {
|
if ( other.getMidpoint() == chainOrigin && other.getDest() == chainMidpoint ) {
|
||||||
// The new chain is a continuation of this chain
|
// The new chain is a continuation of this chain
|
||||||
other.next = chain;
|
other.next = chain;
|
||||||
@@ -1391,8 +1434,56 @@ public class Mesh< T extends Region > {
|
|||||||
} else if ( compare( other.getDest(), chainOrigin ) > 0 ) {
|
} else if ( compare( other.getDest(), chainOrigin ) > 0 ) {
|
||||||
// Do the chains even overlap?
|
// Do the chains even overlap?
|
||||||
if ( chainOrigin == other.getMidpoint() ) {
|
if ( chainOrigin == other.getMidpoint() ) {
|
||||||
chain.intersections.add( other );
|
// In the case that the new chain's origin is another chain's midpoint,
|
||||||
|
// we need to check which direction the other chain is facing.
|
||||||
|
// This is because the new chain only counts as intersecting with the other
|
||||||
|
// chain if and only if the creation of this chain would prevent the other
|
||||||
|
// chain from being linked correctly.
|
||||||
|
|
||||||
|
final Vector2d otherDirection = other.getDest().getPosition().subtracted( other.getOrigin().getPosition() );
|
||||||
|
final double cross = otherDirection.cross( r );
|
||||||
|
|
||||||
|
boolean intersects = true;
|
||||||
|
final HalfEdge firstLink = other.links.get( 0 );
|
||||||
|
final HalfEdge secondLink = other.links.get( 1 );
|
||||||
|
if ( firstLink.getDest() == other.getMidpoint() ) {
|
||||||
|
// Is the first link a direct connection?
|
||||||
|
intersects = interior.contains( firstLink ) ^ cross < 0;
|
||||||
|
} else if ( secondLink.getDest() == other.getDest() ) {
|
||||||
|
// Is the second link a direct connection?
|
||||||
|
intersects = interior.contains( secondLink ) ^ cross < 0;
|
||||||
|
} else {
|
||||||
|
// The chain is comprised of only vertices...
|
||||||
|
intersects = otherDirection.cross( secondLink.toVector2d() ) < 0 ^ cross < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( intersects ) {
|
||||||
|
synchronized ( intersections ) {
|
||||||
|
intersections.add( other );
|
||||||
|
}
|
||||||
other.intersections.add( chain );
|
other.intersections.add( chain );
|
||||||
|
}
|
||||||
|
} else if ( other.getDest() == chainMidpoint ) {
|
||||||
|
// Likewise, the new chain's midpoint may be another existing chain's
|
||||||
|
// destination. We need to check for that case too.
|
||||||
|
final Vector2d otherDirection = other.getOrigin().getPosition().subtracted( other.getDest().getPosition() ).normalize();
|
||||||
|
final double cross = r.cross( otherDirection );
|
||||||
|
|
||||||
|
boolean intersects = true;
|
||||||
|
if ( firstEdge.getDest() == chainMidpoint ) {
|
||||||
|
intersects = interior.contains( firstEdge ) ^ cross < 0;
|
||||||
|
} else if ( secondEdge.getDest() == chainDestination ) {
|
||||||
|
intersects = interior.contains( secondEdge ) ^ cross < 0;
|
||||||
|
} else {
|
||||||
|
intersects = r.cross( secondEdgeVec ) < 0 ^ cross < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( intersects ) {
|
||||||
|
synchronized ( intersections ) {
|
||||||
|
intersections.add( other );
|
||||||
|
}
|
||||||
|
other.intersections.add( chain );
|
||||||
|
}
|
||||||
} else if ( other.getOrigin() != chainOrigin && other.getDest() != chainDestination ) {
|
} else if ( other.getOrigin() != chainOrigin && other.getDest() != chainDestination ) {
|
||||||
// Make sure the chains don't share the same origin or destination
|
// Make sure the chains don't share the same origin or destination
|
||||||
|
|
||||||
@@ -1411,20 +1502,23 @@ public class Mesh< T extends Region > {
|
|||||||
final double t = pq.cross( s ) / rs;
|
final double t = pq.cross( s ) / rs;
|
||||||
final double u = pqr / rs;
|
final double u = pqr / rs;
|
||||||
|
|
||||||
|
final double tTol = VERTEX_TOLERANCE / r.length();
|
||||||
final double uTol = VERTEX_TOLERANCE / s.length();
|
final double uTol = VERTEX_TOLERANCE / s.length();
|
||||||
|
|
||||||
// Do the line segments intersect
|
// Do the line segments intersect
|
||||||
// Allow for overlap
|
// Allow for overlap
|
||||||
if ( t >= 0 && t <= 1 && u > -uTol && u < ( 1 + uTol ) ) {
|
if ( t > -tTol && t < ( 1 + tTol ) && u > -uTol && u < ( 1 + uTol ) ) {
|
||||||
// The chains intersect! We don't care about where.
|
// The chains intersect! We don't care about where.
|
||||||
|
|
||||||
chain.intersections.add( other );
|
synchronized ( intersections ) {
|
||||||
|
intersections.add( other );
|
||||||
|
}
|
||||||
other.intersections.add( chain );
|
other.intersections.add( chain );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} );
|
||||||
chains.add( chain );
|
chains.add( chain );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1487,7 +1581,7 @@ public class Mesh< T extends Region > {
|
|||||||
final Map< HalfEdge, Partition > lowerEdgeMap = new HashMap< HalfEdge, Partition >();
|
final Map< HalfEdge, Partition > lowerEdgeMap = new HashMap< HalfEdge, Partition >();
|
||||||
|
|
||||||
// Keep track of all completed chain links that we have
|
// Keep track of all completed chain links that we have
|
||||||
final Collection< Chain > chains = new HashSet< Chain >();
|
final Collection< Link > chains = new LinkedHashSet< Link >();
|
||||||
|
|
||||||
// Keep track of edges from bottom top
|
// Keep track of edges from bottom top
|
||||||
final SortedEdgeCollection< HalfEdge > edgeCollection = new SortedEdgeCollection< HalfEdge >( Mesh::greaterThanOrEqualTo );
|
final SortedEdgeCollection< HalfEdge > edgeCollection = new SortedEdgeCollection< HalfEdge >( Mesh::greaterThanOrEqualTo );
|
||||||
@@ -1620,30 +1714,21 @@ public class Mesh< T extends Region > {
|
|||||||
// Create a new visibility region
|
// Create a new visibility region
|
||||||
final VisibilityRegion copyRegion = new VisibilityRegion( region.lowerEdge, region.upperEdge );
|
final VisibilityRegion copyRegion = new VisibilityRegion( region.lowerEdge, region.upperEdge );
|
||||||
|
|
||||||
// Update the new region's lower links
|
|
||||||
if ( region.lower != MIN_CROSS ) {
|
|
||||||
copyRegion.lower = region.lower;
|
|
||||||
copyRegion.links.put( region.lower, region.links.remove( region.lower ) );
|
|
||||||
|
|
||||||
// Obviously, whenever we remove a region from the links, we need to check
|
|
||||||
// if the region even has any more links... otherwise it's clearly dead and
|
|
||||||
// needs to be removed entirely.
|
|
||||||
if ( region.links.isEmpty() ) {
|
|
||||||
regionIt.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
region.lower = MIN_CROSS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inherit the upper region's links
|
|
||||||
// This may cause duplication of chains, but
|
// This may cause duplication of chains, but
|
||||||
// we should be able to check them when we add them
|
// we should be able to check them when we add them
|
||||||
// TODO Can this be simplified?
|
// TODO Can this be simplified?
|
||||||
// As in, can we prove that this chain will connect, while
|
// As in, can we prove that this chain will connect, while
|
||||||
// the upper region's chain will not, or vice versa?
|
// the upper region's chain will not, or vice versa?
|
||||||
|
|
||||||
|
// Copy the old region's lower and upper links
|
||||||
|
if ( region.lower != MIN_CROSS ) {
|
||||||
|
copyRegion.lower = region.lower;
|
||||||
|
copyRegion.links.put( region.lower, region.links.get( region.lower ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit the upper region's links
|
||||||
if ( region.upper != MAX_CROSS ) {
|
if ( region.upper != MAX_CROSS ) {
|
||||||
copyRegion.upper = region.upper;
|
copyRegion.upper = region.upper;
|
||||||
|
|
||||||
copyRegion.links.put( region.upper, region.links.get( region.upper ) );
|
copyRegion.links.put( region.upper, region.links.get( region.upper ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1822,19 +1907,17 @@ public class Mesh< T extends Region > {
|
|||||||
throw new IllegalStateException( "Dangling partitions!" );
|
throw new IllegalStateException( "Dangling partitions!" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a chain link, select the links which intersect the least, and remove any that it intersects with from the
|
return chains;
|
||||||
// queue. Essentially, a greedy method, which is more or less guaranteed optimal results.
|
}
|
||||||
// This is also unfortunately an O(n^2) time algorithm that can't be simplified.
|
|
||||||
|
|
||||||
// Keep track of all chains that we want
|
private static Collection< Link > maximizeChains( final Collection< Link > chains ) {
|
||||||
final Collection< Chain > selectedChains = new HashSet< Chain >();
|
final Collection< Link > remainingChains = new LinkedHashSet< Link >( chains );
|
||||||
// Keep track of all remaining chains that needs to be scanned
|
final Collection< Link > selectedChains = new HashSet< Link >();
|
||||||
final Collection< Chain > remainingChains = new HashSet< Chain >( chains );
|
|
||||||
|
|
||||||
// Do a quick scan and remove any chains that have 0 intersections, since we can get
|
// Do a quick scan and remove any chains that have 0 intersections, since we can get
|
||||||
// this done in linear time and all at once
|
// this done in linear time and all at once
|
||||||
for ( final Iterator< Chain > it = remainingChains.iterator(); it.hasNext(); ) {
|
for ( final Iterator< Link > it = remainingChains.iterator(); it.hasNext(); ) {
|
||||||
final Chain chain = it.next();
|
final Link chain = it.next();
|
||||||
|
|
||||||
if ( chain.intersections.size() == 0 ) {
|
if ( chain.intersections.size() == 0 ) {
|
||||||
selectedChains.add( chain );
|
selectedChains.add( chain );
|
||||||
@@ -1845,7 +1928,7 @@ public class Mesh< T extends Region > {
|
|||||||
// Chain links
|
// Chain links
|
||||||
while ( !remainingChains.isEmpty() ) {
|
while ( !remainingChains.isEmpty() ) {
|
||||||
// Find the chain with the least amount of intersections
|
// Find the chain with the least amount of intersections
|
||||||
final Chain least = remainingChains.parallelStream().min( ( c1, c2 ) -> {
|
final Link least = remainingChains.parallelStream().min( ( c1, c2 ) -> {
|
||||||
return Integer.compare( c1.intersections.size(), c2.intersections.size() );
|
return Integer.compare( c1.intersections.size(), c2.intersections.size() );
|
||||||
} ).get();
|
} ).get();
|
||||||
|
|
||||||
@@ -1861,14 +1944,17 @@ public class Mesh< T extends Region > {
|
|||||||
selectedChains.add( least );
|
selectedChains.add( least );
|
||||||
}
|
}
|
||||||
|
|
||||||
final Collection< Chain > cs = new HashSet< Chain >( selectedChains );
|
return selectedChains;
|
||||||
|
}
|
||||||
|
|
||||||
while ( !selectedChains.isEmpty() ) {
|
private static void mergeChains( final Collection< Link > selected, final Collection< HalfEdge > interior ) {
|
||||||
|
final Collection< Link > chains = new HashSet< Link >( selected );
|
||||||
|
while ( !chains.isEmpty() ) {
|
||||||
// Get a chain
|
// Get a chain
|
||||||
Chain chain = selectedChains.iterator().next();
|
Link chain = chains.iterator().next();
|
||||||
|
|
||||||
// Get the head of the chain
|
// Get the head of the chain
|
||||||
while ( selectedChains.contains( chain.previous ) ) {
|
while ( chains.contains( chain.previous ) ) {
|
||||||
chain = chain.previous;
|
chain = chain.previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1893,9 +1979,9 @@ public class Mesh< T extends Region > {
|
|||||||
interior.add( right.getSym() );
|
interior.add( right.getSym() );
|
||||||
}
|
}
|
||||||
|
|
||||||
Chain previousChain;
|
Link previousChain;
|
||||||
do {
|
do {
|
||||||
selectedChains.remove( chain );
|
chains.remove( chain );
|
||||||
|
|
||||||
final HalfEdge head = chain.links.get( 0 );
|
final HalfEdge head = chain.links.get( 0 );
|
||||||
final Vertex origin = chain.getOrigin();
|
final Vertex origin = chain.getOrigin();
|
||||||
@@ -2045,7 +2131,7 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
|
|
||||||
previousChain = chain;
|
previousChain = chain;
|
||||||
} while ( ( chain = chain.next ) != null && selectedChains.contains( chain ) );
|
} while ( ( chain = chain.next ) != null && chains.contains( chain ) );
|
||||||
|
|
||||||
// Terminate the chain
|
// Terminate the chain
|
||||||
final Vertex destination = previousChain.getDest();
|
final Vertex destination = previousChain.getDest();
|
||||||
@@ -2087,8 +2173,6 @@ public class Mesh< T extends Region > {
|
|||||||
left.getSym().setOrigin( destination );
|
left.getSym().setOrigin( destination );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the vertex's edge as the hint, basically because we have no better edge to start from
|
// Use the vertex's edge as the hint, basically because we have no better edge to start from
|
||||||
@@ -2111,6 +2195,8 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
final Vector2d normalized = vector.normalized();
|
final Vector2d normalized = vector.normalized();
|
||||||
|
|
||||||
|
int size = vertex.size();
|
||||||
|
|
||||||
// This is a fairly simple use case, so compare absolute angles
|
// This is a fairly simple use case, so compare absolute angles
|
||||||
HalfEdge edge = hint;
|
HalfEdge edge = hint;
|
||||||
while ( true ) {
|
while ( true ) {
|
||||||
@@ -2127,6 +2213,10 @@ public class Mesh< T extends Region > {
|
|||||||
lowest = angle;
|
lowest = angle;
|
||||||
}
|
}
|
||||||
edge = edge.getPrev();
|
edge = edge.getPrev();
|
||||||
|
|
||||||
|
if ( --size < 0 ) {
|
||||||
|
throw new IllegalStateException( "Not good vertex! With only " + vertex.size() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2445,7 +2535,7 @@ public class Mesh< T extends Region > {
|
|||||||
return newPolygons;
|
return newPolygons;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection< EdgePolygon > triangulate( final EdgePolygon polygon ) {
|
private static Collection< Polygon > triangulate( final EdgePolygon polygon ) {
|
||||||
// Go down each monotone chain and connect the vertices where possible.
|
// Go down each monotone chain and connect the vertices where possible.
|
||||||
// Implements the O(n) triangulation of a polygon as described in
|
// Implements the O(n) triangulation of a polygon as described in
|
||||||
// Computation Geometry Algorithms and Applications 3rd Ed.
|
// Computation Geometry Algorithms and Applications 3rd Ed.
|
||||||
@@ -2454,7 +2544,7 @@ public class Mesh< T extends Region > {
|
|||||||
if ( polygon.getEdges().size() < 3 || polygon.getVertices().size() < 3 ) {
|
if ( polygon.getEdges().size() < 3 || polygon.getVertices().size() < 3 ) {
|
||||||
throw new IllegalStateException( "Invalid amount of verts/edges!" );
|
throw new IllegalStateException( "Invalid amount of verts/edges!" );
|
||||||
} else if ( polygon.getEdges().size() == 3 ) {
|
} else if ( polygon.getEdges().size() == 3 ) {
|
||||||
return Arrays.asList( polygon );
|
return Arrays.asList( new Polygon( polygon.getVertices().stream().map( v -> new Point( v.getPosition() ) ).toList() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
final Queue< HalfEdge > edges = new PriorityQueue< HalfEdge >( ( a, b ) -> {
|
final Queue< HalfEdge > edges = new PriorityQueue< HalfEdge >( ( a, b ) -> {
|
||||||
@@ -2553,22 +2643,21 @@ public class Mesh< T extends Region > {
|
|||||||
// Eventually we will remove this
|
// Eventually we will remove this
|
||||||
toSort.parallelStream().forEach( v -> sort( v ) );
|
toSort.parallelStream().forEach( v -> sort( v ) );
|
||||||
|
|
||||||
// TODO Convert to triangles or something?
|
final Collection< Polygon > polygons = new ArrayDeque< Polygon >();
|
||||||
final Collection< EdgePolygon > polygons = new ArrayDeque< EdgePolygon >();
|
|
||||||
final Set< HalfEdge > scanned = new HashSet< HalfEdge >();
|
final Set< HalfEdge > scanned = new HashSet< HalfEdge >();
|
||||||
for ( final HalfEdge edge : polygon.getEdges() ) {
|
for ( final HalfEdge edge : polygon.getEdges() ) {
|
||||||
if ( scanned.add( edge ) ) {
|
if ( scanned.add( edge ) ) {
|
||||||
HalfEdge temp = edge;
|
HalfEdge temp = edge;
|
||||||
EdgePolygon poly = new EdgePolygon();
|
|
||||||
|
|
||||||
|
final List< Point > points = new ArrayList< Point >();
|
||||||
do {
|
do {
|
||||||
poly.addEdge( temp );
|
points.add( new Point( temp.getOrigin().getPosition() ) );
|
||||||
} while ( scanned.add( temp = temp.getNext() ) );
|
} while ( scanned.add( temp = temp.getNext() ) );
|
||||||
|
|
||||||
if ( poly.getVertices().size() != 3 ) {
|
if ( points.size() != 3 ) {
|
||||||
throw new IllegalStateException( "Not a triangle! " + poly.getVertices().size() );
|
throw new IllegalStateException( "Not a triangle: " + points.size() );
|
||||||
}
|
}
|
||||||
polygons.add( poly );
|
polygons.add( new Polygon( points ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2702,7 +2791,7 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EdgePolygon {
|
private static class EdgePolygon {
|
||||||
private Set< HalfEdge > edges = new HashSet< HalfEdge >();
|
private Set< HalfEdge > edges = new HashSet< HalfEdge >();
|
||||||
private Set< Vertex > vertices = new HashSet< Vertex >();
|
private Set< Vertex > vertices = new HashSet< Vertex >();
|
||||||
|
|
||||||
@@ -2720,6 +2809,36 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class Link {
|
||||||
|
List< HalfEdge > links;
|
||||||
|
Set< Link > intersections = new LinkedHashSet< Link >();
|
||||||
|
Link previous;
|
||||||
|
Link next;
|
||||||
|
|
||||||
|
Link( final Collection< HalfEdge > links ) {
|
||||||
|
this.links = new ArrayList< HalfEdge >( links );
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex getOrigin() {
|
||||||
|
return links.get( 0 ).getOrigin();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex getMidpoint() {
|
||||||
|
return links.get( 1 ).getOrigin();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex getDest() {
|
||||||
|
return links.get( 2 ).getOrigin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static interface MeshEventHandler {
|
||||||
|
default void onChainGenerationEvent( final Collection< Chain > chains ) {};
|
||||||
|
default void onPreChainMergeEvent( final Collection< Chain > chains ) {};
|
||||||
|
default void onPartitionEvent( final Collection< Polygon > polygons ) {};
|
||||||
|
}
|
||||||
|
|
||||||
protected enum MeshState {
|
protected enum MeshState {
|
||||||
DIRTY,
|
DIRTY,
|
||||||
SIMPLIFIED,
|
SIMPLIFIED,
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ package com.aaaaahhhhhhh.bananapuncher714.mesh;
|
|||||||
public class Point {
|
public class Point {
|
||||||
protected double x, y;
|
protected double x, y;
|
||||||
|
|
||||||
|
public Point( final Point other ) {
|
||||||
|
this( other.x, other.y );
|
||||||
|
}
|
||||||
|
|
||||||
public Point( double x, double y ) {
|
public Point( double x, double y ) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.mesh;
|
||||||
|
|
||||||
|
public class Segment {
|
||||||
|
private final Point start;
|
||||||
|
private final Point end;
|
||||||
|
|
||||||
|
public Segment( Point start, Point end ) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.MouseInfo;
|
import java.awt.MouseInfo;
|
||||||
@@ -22,20 +24,22 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.EdgeSet;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.HalfEdge;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.HalfEdge;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.Chain;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshEventHandler;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.EdgePolygon;
|
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Vector2d;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Vector2d;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Vertex;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Vertex;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding;
|
||||||
@@ -69,11 +73,10 @@ public class MeshingTest2 extends JPanel {
|
|||||||
|
|
||||||
private double scale = 8;
|
private double scale = 8;
|
||||||
|
|
||||||
private Collection< Vertex > data;
|
private PlaneData data;
|
||||||
private Collection< EdgePolygon > polygons;
|
|
||||||
|
|
||||||
// Temporary... Remove at some point
|
private int stringBoardX = -100;
|
||||||
private static Collection< Chain > chains;
|
private int stringBoardY = 20;
|
||||||
|
|
||||||
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() ) {
|
||||||
@@ -91,28 +94,31 @@ public class MeshingTest2 extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collections.sort( planes, ( a, b ) -> Integer.compare( b.polygons.size(), a.polygons.size() ) );
|
||||||
|
// draw = planes.get( 4 );
|
||||||
|
|
||||||
// Select a random plane to draw
|
// Select a random plane to draw
|
||||||
// draw = planes.get( new Random().nextInt( planes.size() ) );
|
// draw = planes.get( new Random().nextInt( planes.size() ) );
|
||||||
|
|
||||||
System.out.println( "Draw is " + draw );
|
System.out.println( "Draw is " + draw );
|
||||||
// Attempt to mesh all planes
|
// Attempt to mesh all planes
|
||||||
try {
|
// try {
|
||||||
test( planes );
|
// test( planes );
|
||||||
} catch ( PolygonException e ) {
|
// } catch ( PolygonException e ) {
|
||||||
draw = e.getPlane();
|
// draw = e.getPlane();
|
||||||
System.out.println( "Draw is now " + draw );
|
// System.out.println( "Draw is now " + draw );
|
||||||
}
|
// }
|
||||||
|
|
||||||
final Collection< Vertex > data = process( draw );
|
final PlaneData data = process( draw );
|
||||||
final Collection< EdgePolygon > polys = triangulate( draw );
|
final Collection< Polygon > polys = triangulate( draw );
|
||||||
// final Collection< EdgePolygon > polys = test();
|
// final Collection< Polygon > polys = test();
|
||||||
|
|
||||||
System.out.println( "Polygon count: " + polys.size() );
|
System.out.println( "Polygon count: " + polys.size() );
|
||||||
|
|
||||||
SwingUtilities.invokeLater( new Runnable() {
|
SwingUtilities.invokeLater( new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
new MeshingTest2( data, polys );
|
new MeshingTest2( data );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
break;
|
break;
|
||||||
@@ -190,7 +196,7 @@ public class MeshingTest2 extends JPanel {
|
|||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
mesh.simplify();
|
mesh.simplify();
|
||||||
mesh.generateRegions();
|
mesh.generateRegions();
|
||||||
final Collection< EdgePolygon > polys = mesh.copyOf().mesh();
|
final Collection< Polygon > polys = mesh.copyOf().mesh();
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
System.out.println( plane.polygons.size() + " to " + polys.size() + ":\t " + ( end - start ) + "ms" );
|
System.out.println( plane.polygons.size() + " to " + polys.size() + ":\t " + ( end - start ) + "ms" );
|
||||||
} catch ( IllegalStateException e ) {
|
} catch ( IllegalStateException e ) {
|
||||||
@@ -202,8 +208,9 @@ public class MeshingTest2 extends JPanel {
|
|||||||
System.out.println( "Took " + ( processAllEnd - processAllStart ) + "ms to process " + planes.size() + " planes" );
|
System.out.println( "Took " + ( processAllEnd - processAllStart ) + "ms to process " + planes.size() + " planes" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection< Vertex > process( final Plane plane ) {
|
private static PlaneData process( final Plane plane ) {
|
||||||
if ( plane != null ) {
|
if ( plane != null ) {
|
||||||
|
final PlaneData data = new PlaneData();
|
||||||
System.out.println( "Norm:\t" + plane.normal );
|
System.out.println( "Norm:\t" + plane.normal );
|
||||||
System.out.println( "Ref:\t" + plane.point );
|
System.out.println( "Ref:\t" + plane.point );
|
||||||
System.out.println( "Size:\t" + plane.polygons.size() );
|
System.out.println( "Size:\t" + plane.polygons.size() );
|
||||||
@@ -214,30 +221,46 @@ public class MeshingTest2 extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
System.out.println( "Initial vertex count: " + mesh.getVertices().size() );
|
System.out.println( "Initial vertex count: " + mesh.getVertices().size() );
|
||||||
System.out.println( "Initial edge count: " + ( mesh.getRuleSize() / 2 ) );
|
System.out.println( "Initial edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
mesh.simplify();
|
mesh.simplify();
|
||||||
|
|
||||||
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.getRuleSize() / 2 ) );
|
System.out.println( "After simplify edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
mesh.generateRegions();
|
mesh.generateRegions();
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
|
|
||||||
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
|
data.vertices = mesh.getVertices();
|
||||||
System.out.println( "After generating regions edge count: " + ( mesh.getRuleSize() / 2 ) );
|
data.edges = mesh.getEdges();
|
||||||
|
|
||||||
|
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
|
||||||
|
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
|
mesh.addHandler( new MeshEventHandler() {
|
||||||
|
@Override
|
||||||
|
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||||
|
data.chains = chains;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreChainMergeEvent( Collection< Chain > chains ) {
|
||||||
|
data.selectedChains = chains;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
data.polygons = mesh.mesh();
|
||||||
|
|
||||||
System.out.println( "Took " + ( end - start ) + "ms" );
|
System.out.println( "Took " + ( end - start ) + "ms" );
|
||||||
return mesh.getVertices();
|
return data;
|
||||||
} else {
|
} else {
|
||||||
System.out.println( "No data!" );
|
System.out.println( "No data!" );
|
||||||
return Collections.emptySet();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection< EdgePolygon > triangulate( final Plane plane ) {
|
private static Collection< Polygon > triangulate( final Plane plane ) {
|
||||||
if ( plane != null ) {
|
if ( plane != null ) {
|
||||||
System.out.println( "Norm:\t" + plane.normal );
|
System.out.println( "Norm:\t" + plane.normal );
|
||||||
System.out.println( "Ref:\t" + plane.point );
|
System.out.println( "Ref:\t" + plane.point );
|
||||||
@@ -249,32 +272,28 @@ public class MeshingTest2 extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
System.out.println( "Initial vertex count: " + mesh.getVertices().size() );
|
System.out.println( "Initial vertex count: " + mesh.getVertices().size() );
|
||||||
System.out.println( "Initial edge count: " + ( mesh.getRuleSize() / 2 ) );
|
System.out.println( "Initial edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
mesh.simplify();
|
mesh.simplify();
|
||||||
|
|
||||||
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.getRuleSize() / 2 ) );
|
System.out.println( "After simplify edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
mesh.generateRegions();
|
mesh.generateRegions();
|
||||||
|
|
||||||
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.getRuleSize() / 2 ) );
|
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
// Make sure this works
|
// Make sure this works
|
||||||
mesh = mesh.copyOf();
|
mesh = mesh.copyOf();
|
||||||
|
|
||||||
Collection< EdgePolygon > polys;
|
Collection< Polygon > polys = new HashSet< Polygon >();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
polys = mesh.mesh();
|
polys = mesh.mesh();
|
||||||
chains = mesh.chains;
|
|
||||||
} catch ( IllegalStateException e ) {
|
} catch ( IllegalStateException e ) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
||||||
polys = mesh.mesh( );
|
|
||||||
chains = mesh.chains;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
@@ -287,7 +306,7 @@ public class MeshingTest2 extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection< EdgePolygon > test() {
|
private static Collection< Polygon > test() {
|
||||||
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||||
|
|
||||||
// mesh.addPolygon( new Polygon( Arrays.asList(
|
// mesh.addPolygon( new Polygon( Arrays.asList(
|
||||||
@@ -409,20 +428,37 @@ public class MeshingTest2 extends JPanel {
|
|||||||
// new Point( 2.8151429293905887, -2.747294403063162 )
|
// new Point( 2.8151429293905887, -2.747294403063162 )
|
||||||
// ) ), RegionRuleWinding.CLOCKWISE );
|
// ) ), 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 );
|
||||||
|
|
||||||
mesh.simplify();
|
mesh.simplify();
|
||||||
|
|
||||||
mesh.generateRegions();
|
mesh.generateRegions();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Collection< EdgePolygon > polys = mesh.mesh();
|
final Collection< Polygon > polys = mesh.mesh();
|
||||||
chains = mesh.chains;
|
|
||||||
return polys;
|
return polys;
|
||||||
} catch ( Exception e ) {
|
} catch ( Exception e ) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Collection< EdgePolygon > polys = mesh.mesh();
|
final Collection< Polygon > polys = mesh.mesh();
|
||||||
chains = mesh.chains;
|
|
||||||
|
|
||||||
return polys;
|
return polys;
|
||||||
}
|
}
|
||||||
@@ -526,9 +562,8 @@ public class MeshingTest2 extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MeshingTest2( Collection< Vertex > polys, Collection< EdgePolygon > polygons ) {
|
public MeshingTest2( PlaneData data ) {
|
||||||
data = polys;
|
this.data = data;
|
||||||
this.polygons = polygons;
|
|
||||||
|
|
||||||
f = new JFrame( "Drawing Board" );
|
f = new JFrame( "Drawing Board" );
|
||||||
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
|
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
|
||||||
@@ -596,6 +631,14 @@ public class MeshingTest2 extends JPanel {
|
|||||||
};
|
};
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// final JPanel taskbar = new JPanel();
|
||||||
|
// taskbar.setLayout( new FlowLayout() );
|
||||||
|
//
|
||||||
|
// taskbar.add( new JButton( "Previous" ) );
|
||||||
|
// taskbar.add( new JButton( "Next" ) );
|
||||||
|
//
|
||||||
|
// f.add( taskbar, BorderLayout.NORTH );
|
||||||
|
|
||||||
f.add( this );
|
f.add( this );
|
||||||
|
|
||||||
f.setSize( windowWidth, windowHeight );
|
f.setSize( windowWidth, windowHeight );
|
||||||
@@ -613,6 +656,11 @@ public class MeshingTest2 extends JPanel {
|
|||||||
return new Vector2d( ax, ay );
|
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
|
@Override
|
||||||
public void paintComponent( Graphics g ) {
|
public void paintComponent( Graphics g ) {
|
||||||
super.paintComponent( g );
|
super.paintComponent( g );
|
||||||
@@ -624,17 +672,16 @@ public class MeshingTest2 extends JPanel {
|
|||||||
|
|
||||||
int highestX = 40;
|
int highestX = 40;
|
||||||
if ( data != null ) {
|
if ( data != null ) {
|
||||||
Collection< Vertex > polygons = data;
|
if ( !data.edges.isEmpty() ) {
|
||||||
|
Collection< Point > points = data.vertices;
|
||||||
|
|
||||||
highestX = ( int ) ( polygons.parallelStream()
|
highestX = ( int ) ( points.parallelStream()
|
||||||
.max( ( a, b ) -> { return Double.compare( a.getPosition().getX(), b.getPosition().getX() ); } ).get().getPosition().getX() + 40.5 );
|
.max( ( a, b ) -> { return Double.compare( a.getX(), b.getX() ); } ).get().getX() + 40.5 );
|
||||||
|
|
||||||
EdgeSet edges = new EdgeSet();
|
g.setColor( Color.BLACK );
|
||||||
for ( Vertex vert : polygons ) {
|
for ( final Segment segment : data.edges ) {
|
||||||
for ( HalfEdge edge : vert ) {
|
Point p1 = segment.getStart();
|
||||||
if ( edges.add( edge ) ) {
|
Point p2 = segment.getEnd();
|
||||||
Point p1 = edge.getOrigin().getPosition();
|
|
||||||
Point p2 = edge.getDest().getPosition();
|
|
||||||
g.drawLine(
|
g.drawLine(
|
||||||
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX,
|
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX,
|
||||||
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY,
|
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY,
|
||||||
@@ -642,113 +689,100 @@ public class MeshingTest2 extends JPanel {
|
|||||||
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY
|
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
for ( final Point point : points ) {
|
||||||
final double diff = scale * 0.15;
|
final double diff = scale * 0.15;
|
||||||
final Point point = vert.getPosition();
|
|
||||||
g.setColor( Color.BLACK );
|
|
||||||
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 ) );
|
g.drawRect( ( int ) ( ( centerX + point.getX() + highestX ) * scale ) - ( int ) diff + offsetX, ( int ) ( ( centerY - point.getY() ) * scale ) - ( int ) diff + offsetY, ( int ) ( diff * 2 ), ( int ) ( diff * 2 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawOnBoard( g, "Edge count: " + data.edges.size(), 0, 0 );
|
||||||
|
drawOnBoard( g, "Vertex count: " + points.size(), 0, -5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( polygons != null ) {
|
if ( data.polygons != null ) {
|
||||||
g.setColor( Color.BLACK );
|
|
||||||
int count = 2;
|
int count = 2;
|
||||||
Random random = new Random( hashCode() );
|
Random random = new Random( hashCode() );
|
||||||
|
|
||||||
final int spacing = 25;
|
final int spacing = 25;
|
||||||
for ( final EdgePolygon p : polygons ) {
|
|
||||||
final Collection< HalfEdge > edges = p.getEdges();
|
|
||||||
|
|
||||||
final Set< Vertex > verts = new HashSet< Vertex >();
|
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.setColor( Color.BLACK );
|
||||||
for ( HalfEdge edge : edges ) {
|
g.drawPolygon( x, y, points.size() );
|
||||||
Point p1 = edge.getOrigin().getPosition();
|
g.drawPolygon( xOffset, yOffset, points.size() );
|
||||||
Point p2 = edge.getDest().getPosition();
|
|
||||||
g.drawLine(
|
|
||||||
( int ) ( ( centerX + p1.getX() + count * spacing ) * scale ) + offsetX,
|
|
||||||
( int ) ( ( centerY - p1.getY() - 150 ) * scale ) + offsetY,
|
|
||||||
( int ) ( ( centerX + p2.getX() + count * spacing ) * scale ) + offsetX,
|
|
||||||
( int ) ( ( centerY - p2.getY() - 150 ) * scale ) + offsetY
|
|
||||||
);
|
|
||||||
|
|
||||||
g.drawLine(
|
|
||||||
( int ) ( ( centerX + p1.getX() ) * scale ) + offsetX,
|
|
||||||
( int ) ( ( centerY - p1.getY() - 150 ) * scale ) + offsetY,
|
|
||||||
( int ) ( ( centerX + p2.getX() ) * scale ) + offsetX,
|
|
||||||
( int ) ( ( centerY - p2.getY() - 150 ) * scale ) + offsetY
|
|
||||||
);
|
|
||||||
|
|
||||||
final double diff = scale * 0.15;
|
|
||||||
if ( !verts.add( edge.getOrigin() ) ) {
|
|
||||||
g.drawRect( ( int ) ( ( centerX + p1.getX() + count * spacing ) * scale ) - ( int ) diff + offsetX, ( int ) ( ( centerY - p1.getY() - 150 ) * scale ) - ( int ) diff + offsetY, ( int ) ( diff * 2 ), ( int ) ( diff * 2 ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
|
|
||||||
int size = edges.size();
|
|
||||||
int[] xPoints = new int[ size ];
|
|
||||||
int[] yPoints = new int[ size ];
|
|
||||||
|
|
||||||
final Set< Vertex > verts2 = new HashSet< Vertex >();
|
|
||||||
|
|
||||||
HalfEdge edge = edges.iterator().next();
|
|
||||||
for ( int i = 0; i < edges.size(); ++i ) {
|
|
||||||
final Point point = edge.getOrigin().getPosition();
|
|
||||||
xPoints[ i ] = ( int ) ( ( centerX + point.getX() ) * scale ) + offsetX;
|
|
||||||
yPoints[ i ] = ( int ) ( ( centerY - point.getY() ) * scale ) + offsetY;
|
|
||||||
|
|
||||||
final double diff = scale * 0.15;
|
|
||||||
if ( !verts2.add( edge.getOrigin() ) ) {
|
|
||||||
g.setColor( Color.ORANGE );
|
|
||||||
} else {
|
|
||||||
g.setColor( Color.BLACK );
|
|
||||||
}
|
|
||||||
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 ) );
|
|
||||||
|
|
||||||
edge = edge.getNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setColor( new Color( random.nextInt( 0x1000000 ) ) );
|
g.setColor( new Color( random.nextInt( 0x1000000 ) ) );
|
||||||
g.fillPolygon( xPoints, yPoints, size );
|
g.fillPolygon( filledX, filledY, points.size() );
|
||||||
}
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( chains != null ) {
|
g.setColor( Color.MAGENTA );
|
||||||
int i = 0;
|
drawOnBoard( g, "Polygon count: " + data.polygons.size(), 0, -10 );
|
||||||
for ( Chain chain : chains ) {
|
}
|
||||||
Point p1 = chain.getOrigin().getPosition();
|
|
||||||
Point p2 = chain.getDest().getPosition();
|
if ( data.chains != null ) {
|
||||||
g.setColor( Color.RED );
|
g.setColor( Color.RED );
|
||||||
g.drawLine(
|
for ( final Chain chain : data.chains ) {
|
||||||
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX + i,
|
final Point p1 = chain.getStart();
|
||||||
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY + i,
|
final Point p2 = chain.getEnd();
|
||||||
( int ) ( ( centerX + p2.getX() + highestX ) * scale ) + offsetX + i,
|
|
||||||
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY + i
|
|
||||||
);
|
|
||||||
|
|
||||||
// for ( HalfEdge e : chain.getLinks() ) {
|
g.drawLine(
|
||||||
// Point e1 = e.getOrigin().getPosition();
|
( int ) ( ( centerX + p1.getX() + highestX ) * scale ) + offsetX,
|
||||||
// Point e2 = e.getSym().getOrigin().getPosition();
|
( int ) ( ( centerY - p1.getY() ) * scale ) + offsetY,
|
||||||
// g.setColor( Color.BLUE );
|
( int ) ( ( centerX + p2.getX() + highestX ) * scale ) + offsetX,
|
||||||
// g.drawLine(
|
( int ) ( ( centerY - p2.getY() ) * scale ) + offsetY
|
||||||
// ( int ) ( ( centerX + e1.getX() + 40 ) * scale ) + offsetX + i + 1,
|
);
|
||||||
// ( int ) ( ( centerY - e1.getY() ) * scale ) + offsetY + i + 1,
|
}
|
||||||
// ( int ) ( ( centerX + e2.getX() + 40 ) * scale ) + offsetX + i + 1,
|
|
||||||
// ( int ) ( ( centerY - e2.getY() ) * scale ) + offsetY + i + 1
|
drawOnBoard( g, "Chain count: " + data.chains.size(), 0, -15 );
|
||||||
// );
|
}
|
||||||
// }
|
|
||||||
// i += 2;
|
if ( data.selectedChains != null ) {
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
drawOnBoard( g, "Minimum chain count: " + data.selectedChains.size(), 0, -20 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
java.awt.Point p = MouseInfo.getPointerInfo().getLocation();
|
java.awt.Point p = MouseInfo.getPointerInfo().getLocation();
|
||||||
java.awt.Point componentLocation = getLocation();
|
java.awt.Point componentLocation = getLocationOnScreen();
|
||||||
SwingUtilities.convertPointToScreen( componentLocation, this );
|
|
||||||
p = new java.awt.Point( p.x - componentLocation.x, p.y - componentLocation.y );
|
p = new java.awt.Point( p.x - componentLocation.x, p.y - componentLocation.y );
|
||||||
g.setColor( Color.RED );
|
g.setColor( Color.RED );
|
||||||
g.setFont( new Font( Font.MONOSPACED, Font.BOLD, 30 ) );
|
g.setFont( new Font( Font.MONOSPACED, Font.BOLD, 30 ) );
|
||||||
g.drawString( "X: " + ( ( p.x - offsetX ) / scale - centerX ), 10, 30 );
|
g.drawString( "X: " + ( ( p.x - offsetX ) / scale - centerX ), 10, 30 );
|
||||||
g.drawString( "Y: " + ( - ( ( p.y - offsetY ) / scale - centerY ) ), 10, 60 );
|
g.drawString( "Y: " + ( - ( ( p.y - offsetY ) / scale - centerY ) ), 10, 60 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PlaneData {
|
||||||
|
Collection< Point > vertices;
|
||||||
|
Collection< Segment > edges;
|
||||||
|
Collection< Chain > chains;
|
||||||
|
Collection< Chain > selectedChains;
|
||||||
|
Collection< Polygon > polygons;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user