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
202 lines
5.7 KiB
Java
202 lines
5.7 KiB
Java
package com.aaaaahhhhhhh.bananapuncher714.mesh;
|
|
|
|
/**
|
|
* A half-edge class used to represent a DCEL(doubly connected edge list): https://en.wikipedia.org/wiki/Doubly_connected_edge_list
|
|
*
|
|
* In this case, it is intended to be used for a 2d PSLG(planar straight-line graph), but can probably be repurposed
|
|
* for some other nefarious use case.
|
|
*
|
|
* An edge is a line segment connecting an origin to a destination. A half-edge is a partial line segment containing only
|
|
* the origin, but not the destination.
|
|
*
|
|
* Each half-edge structure contains:
|
|
* - A reference to the origin
|
|
* - A reference to the symmetrical, or opposite half-edge which is attached to the destination.
|
|
* - A reference to the next clockwise half-edge of the opposite half edge. This can be used to
|
|
* traverse counter-clockwise through the half-edges of a polygon.
|
|
* - A reference to the previous edge, which is the next counter-clockwise edge of this half edge.
|
|
* This can be used to traverse all the edges of a vertex, in counter clockwise order.
|
|
*
|
|
* For a given half-edge attached to two points that contain no other edges, the previous edge is
|
|
* itself, and the next edge is the same as the opposite edge.
|
|
*
|
|
* There are 2 main operations that are used when manipulating half-edges to attach/detach them from
|
|
* a vertex:
|
|
* - splicing
|
|
* - splitting
|
|
*
|
|
* Splicing is the most important of the 2 operations, by a large margin. Given two half-edges, A and B,
|
|
* swap the previous edges, and set the next edge for both of the previous edges to the opposite half edge.
|
|
* This has the desired effect of either detaching two edges if they are connected to the same vertex, or
|
|
* attaching two separate half-edges together to the same vertex.
|
|
*
|
|
* Splitting is adding an edge between the opposite of an edge and attaching it to the destination. It
|
|
* splits a single edge into two edges with a vertex in the middle.
|
|
*
|
|
* @author BananaPuncher714
|
|
*/
|
|
public class HalfEdge {
|
|
/**
|
|
* The origin
|
|
*/
|
|
protected Vertex origin;
|
|
|
|
/**
|
|
* The symmetrical half-edge
|
|
*/
|
|
protected HalfEdge sym;
|
|
/**
|
|
* The half-edge counter-clockwise on the same origin
|
|
*/
|
|
protected HalfEdge prev;
|
|
/**
|
|
* The half-edge clockwise from the symmetrical half-edge
|
|
*/
|
|
protected HalfEdge next;
|
|
|
|
// TODO Consider adding a constructor with a origin and destination
|
|
|
|
public HalfEdge() {
|
|
init();
|
|
|
|
// Whenever we create a new half-edge, we need to make
|
|
// sure that it has a symmetrical half-edge.
|
|
new HalfEdge( this );
|
|
}
|
|
|
|
private HalfEdge( HalfEdge o ) {
|
|
init();
|
|
|
|
sym = o;
|
|
o.sym = this;
|
|
|
|
next = o;
|
|
o.next = this;
|
|
}
|
|
|
|
private void init() {
|
|
origin = new Vertex( this );
|
|
prev = this;
|
|
}
|
|
|
|
public Vertex getOrigin() {
|
|
return origin;
|
|
}
|
|
|
|
/**
|
|
* Set the origin. Does not affect any additional
|
|
*
|
|
* @param vert
|
|
* @return
|
|
*/
|
|
public HalfEdge setOrigin( Vertex vert ) {
|
|
origin = vert;
|
|
return this;
|
|
}
|
|
|
|
public HalfEdge getSym() {
|
|
return sym;
|
|
}
|
|
|
|
public HalfEdge getPrev() {
|
|
return prev;
|
|
}
|
|
|
|
/**
|
|
* Set the previous half-edge. Does not update additional properties.
|
|
*
|
|
* @param edge The half-edge to set as the previous half-edge.
|
|
* @return This half-edge
|
|
*/
|
|
public HalfEdge setPrev( HalfEdge edge ) {
|
|
this.prev = edge;
|
|
return this;
|
|
}
|
|
|
|
public HalfEdge getNext() {
|
|
return next;
|
|
}
|
|
|
|
/**
|
|
* Set the next half-edge. Does not update additional properties.
|
|
*
|
|
* @param edge The half-edge to set as the next half-edge.
|
|
* @return This half-edge
|
|
*/
|
|
public HalfEdge setNext( HalfEdge edge ) {
|
|
this.next = edge;
|
|
return this;
|
|
}
|
|
|
|
public Vertex getDest() {
|
|
return sym.origin;
|
|
}
|
|
|
|
/**
|
|
* Get the difference between the destination position and the origin position
|
|
*
|
|
* @return A vector representing the destination minus the origin
|
|
*/
|
|
public Vector2d toVector2d() {
|
|
return getDest().getPosition().subtracted( getOrigin().getPosition() );
|
|
}
|
|
|
|
/**
|
|
* Check if the origin and destination are the same
|
|
*
|
|
* @return If the origin is equal to the destination
|
|
*/
|
|
public boolean isZero() {
|
|
return getOrigin().equals( getDest() );
|
|
}
|
|
|
|
/**
|
|
* Split this half-edge in half and return the newly created
|
|
* half-edge, as the next half-edge of this half-edge.
|
|
*
|
|
* @return A new half-edge with a default initialized origin.
|
|
*/
|
|
public HalfEdge split() {
|
|
final HalfEdge edge = new HalfEdge();
|
|
|
|
splice( edge, getNext() );
|
|
|
|
splice( getSym(), getNext() );
|
|
splice( getSym(), edge.getSym() );
|
|
|
|
edge.setOrigin( getDest() );
|
|
edge.getOrigin().setEdge( edge );
|
|
|
|
getSym().setOrigin( edge.getDest() );
|
|
getDest().setEdge( getSym() );
|
|
|
|
edge.getOrigin().setEdge( edge );
|
|
|
|
return edge.getSym();
|
|
}
|
|
|
|
/**
|
|
* Splice two half-edges together. A commutative operation.
|
|
*
|
|
* This does _not_ modify any vertices.
|
|
*
|
|
* @param a The first half-edge
|
|
* @param b The second half-edge
|
|
*/
|
|
public static void splice( HalfEdge a, HalfEdge b ) {
|
|
final HalfEdge ap = a.prev;
|
|
final HalfEdge bp = b.prev;
|
|
|
|
a.prev = bp;
|
|
b.prev = ap;
|
|
|
|
ap.sym.next = b;
|
|
bp.sym.next = a;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return String.format( "HalfEdge{orig=%1$s,dest=%2$s}", getOrigin(), getDest() );
|
|
}
|
|
}
|