mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 16:33:15 +01:00
init
This commit is contained in:
commit
df53c08794
66 changed files with 7833 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
*.class
|
||||||
|
/target/
|
||||||
|
/out/
|
||||||
|
/.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
BIN
lib/gluegen-java-src.zip
Normal file
BIN
lib/gluegen-java-src.zip
Normal file
Binary file not shown.
BIN
lib/jogl-java-src.zip
Normal file
BIN
lib/jogl-java-src.zip
Normal file
Binary file not shown.
342
src/cad/Cad.java
Normal file
342
src/cad/Cad.java
Normal file
|
|
@ -0,0 +1,342 @@
|
||||||
|
package cad;
|
||||||
|
|
||||||
|
import com.jogamp.newt.opengl.GLWindow;
|
||||||
|
import com.jogamp.opengl.util.FPSAnimator;
|
||||||
|
|
||||||
|
import javax.media.opengl.GL2;
|
||||||
|
import javax.media.opengl.GLAutoDrawable;
|
||||||
|
import javax.media.opengl.GLCapabilities;
|
||||||
|
import javax.media.opengl.GLEventListener;
|
||||||
|
import javax.media.opengl.GLProfile;
|
||||||
|
import javax.media.opengl.awt.AWTGLAutoDrawable;
|
||||||
|
import javax.media.opengl.awt.GLJPanel;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.awt.event.MouseMotionListener;
|
||||||
|
|
||||||
|
public class Cad implements GLEventListener, MouseListener, MouseMotionListener {
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// Get the default OpenGL profile, reflecting the best for your running platform
|
||||||
|
GLProfile glp = GLProfile.getDefault();
|
||||||
|
// Specifies a set of OpenGL capabilities, based on your profile.
|
||||||
|
GLCapabilities caps = new GLCapabilities(glp);
|
||||||
|
// Create the OpenGL rendering canvas
|
||||||
|
GLWindow window = GLWindow.create(caps);
|
||||||
|
|
||||||
|
// Create a animator that drives canvas' display() at the specified FPS.
|
||||||
|
final FPSAnimator animator = new FPSAnimator(window, 60, true);
|
||||||
|
// final Animator animator = new Animator(window);
|
||||||
|
window.addWindowListener(new com.jogamp.newt.event.WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) {
|
||||||
|
// Use a dedicate thread to run the stop() to ensure that the
|
||||||
|
// animator stops before program exits.
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (animator.isStarted())
|
||||||
|
animator.stop(); // stop the animator loop
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addGLEventListener(new Cad());
|
||||||
|
|
||||||
|
window.setSize(640, 480);
|
||||||
|
window.setTitle("CAD");
|
||||||
|
window.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
|
||||||
|
private int gear1, gear2, gear3;
|
||||||
|
private float angle = 0.0f;
|
||||||
|
|
||||||
|
private int prevMouseX, prevMouseY;
|
||||||
|
private boolean mouseRButtonDown = false;
|
||||||
|
|
||||||
|
public void init(GLAutoDrawable drawable) {
|
||||||
|
// Use debug pipeline
|
||||||
|
// drawable.setGL(new DebugGL(drawable.getGL()));
|
||||||
|
|
||||||
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
|
|
||||||
|
System.err.println("INIT GL IS: " + gl.getClass().getName());
|
||||||
|
|
||||||
|
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
|
||||||
|
|
||||||
|
gl.setSwapInterval(1);
|
||||||
|
|
||||||
|
float pos[] = {5.0f, 5.0f, 10.0f, 0.0f};
|
||||||
|
float red[] = {0.8f, 0.1f, 0.0f, 1.0f};
|
||||||
|
float green[] = {0.0f, 0.8f, 0.2f, 1.0f};
|
||||||
|
float blue[] = {0.2f, 0.2f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos, 0);
|
||||||
|
gl.glEnable(GL2.GL_CULL_FACE);
|
||||||
|
gl.glEnable(GL2.GL_LIGHTING);
|
||||||
|
gl.glEnable(GL2.GL_LIGHT0);
|
||||||
|
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
/* make the gears */
|
||||||
|
gear1 = gl.glGenLists(1);
|
||||||
|
gl.glNewList(gear1, GL2.GL_COMPILE);
|
||||||
|
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, red, 0);
|
||||||
|
gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f);
|
||||||
|
gl.glEndList();
|
||||||
|
|
||||||
|
gear2 = gl.glGenLists(1);
|
||||||
|
gl.glNewList(gear2, GL2.GL_COMPILE);
|
||||||
|
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, green, 0);
|
||||||
|
gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f);
|
||||||
|
gl.glEndList();
|
||||||
|
|
||||||
|
gear3 = gl.glGenLists(1);
|
||||||
|
gl.glNewList(gear3, GL2.GL_COMPILE);
|
||||||
|
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||||
|
gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f);
|
||||||
|
gl.glEndList();
|
||||||
|
|
||||||
|
gl.glEnable(GL2.GL_NORMALIZE);
|
||||||
|
|
||||||
|
if (drawable instanceof AWTGLAutoDrawable) {
|
||||||
|
AWTGLAutoDrawable awtDrawable = (AWTGLAutoDrawable) drawable;
|
||||||
|
awtDrawable.addMouseListener(this);
|
||||||
|
awtDrawable.addMouseMotionListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||||
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
|
|
||||||
|
float h = (float) height / (float) width;
|
||||||
|
|
||||||
|
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||||
|
|
||||||
|
System.err.println("GL_VENDOR: " + gl.glGetString(GL2.GL_VENDOR));
|
||||||
|
System.err.println("GL_RENDERER: " + gl.glGetString(GL2.GL_RENDERER));
|
||||||
|
System.err.println("GL_VERSION: " + gl.glGetString(GL2.GL_VERSION));
|
||||||
|
gl.glLoadIdentity();
|
||||||
|
gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
|
||||||
|
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||||
|
gl.glLoadIdentity();
|
||||||
|
gl.glTranslatef(0.0f, 0.0f, -40.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose(GLAutoDrawable drawable) {
|
||||||
|
System.out.println("Gears.dispose: " + drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(GLAutoDrawable drawable) {
|
||||||
|
// Turn the gears' teeth
|
||||||
|
angle += 2.0f;
|
||||||
|
|
||||||
|
// Get the GL corresponding to the drawable we are animating
|
||||||
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
|
|
||||||
|
// Special handling for the case where the GLJPanel is translucent
|
||||||
|
// and wants to be composited with other Java 2D content
|
||||||
|
if ((drawable instanceof GLJPanel) &&
|
||||||
|
!((GLJPanel) drawable).isOpaque() &&
|
||||||
|
((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
|
||||||
|
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
|
||||||
|
} else {
|
||||||
|
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate the entire assembly of gears based on how the user
|
||||||
|
// dragged the mouse around
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
|
||||||
|
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
|
||||||
|
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Place the first gear and call its display list
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(-3.0f, -2.0f, 0.0f);
|
||||||
|
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glCallList(gear1);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
|
||||||
|
// Place the second gear and call its display list
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(3.1f, -2.0f, 0.0f);
|
||||||
|
gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glCallList(gear2);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
|
||||||
|
// Place the third gear and call its display list
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(-3.1f, 4.2f, 0.0f);
|
||||||
|
gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glCallList(gear3);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
|
||||||
|
// Remember that every push needs a pop; this one is paired with
|
||||||
|
// rotating the entire gear assembly
|
||||||
|
gl.glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void gear(GL2 gl,
|
||||||
|
float inner_radius,
|
||||||
|
float outer_radius,
|
||||||
|
float width,
|
||||||
|
int teeth,
|
||||||
|
float tooth_depth) {
|
||||||
|
int i;
|
||||||
|
float r0, r1, r2;
|
||||||
|
float angle, da;
|
||||||
|
float u, v, len;
|
||||||
|
|
||||||
|
r0 = inner_radius;
|
||||||
|
r1 = outer_radius - tooth_depth / 2.0f;
|
||||||
|
r2 = outer_radius + tooth_depth / 2.0f;
|
||||||
|
|
||||||
|
da = 2.0f * (float) Math.PI / teeth / 4.0f;
|
||||||
|
|
||||||
|
gl.glShadeModel(GL2.GL_FLAT);
|
||||||
|
|
||||||
|
gl.glNormal3f(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
/* draw front face */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i <= teeth; i++) {
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), width * 0.5f);
|
||||||
|
if (i < teeth) {
|
||||||
|
gl.glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle + 3.0f * da), r1 * (float) Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw front sides of teeth */
|
||||||
|
gl.glBegin(GL2.GL_QUADS);
|
||||||
|
for (i = 0; i < teeth; i++) {
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + 2.0f * da), r2 * (float) Math.sin(angle + 2.0f * da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle + 3.0f * da), r1 * (float) Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw back face */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i <= teeth; i++) {
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), -width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw back sides of teeth */
|
||||||
|
gl.glBegin(GL2.GL_QUADS);
|
||||||
|
for (i = 0; i < teeth; i++) {
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + 2 * da), r2 * (float) Math.sin(angle + 2 * da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), -width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw outward faces of teeth */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i < teeth; i++) {
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), -width * 0.5f);
|
||||||
|
u = r2 * (float) Math.cos(angle + da) - r1 * (float) Math.cos(angle);
|
||||||
|
v = r2 * (float) Math.sin(angle + da) - r1 * (float) Math.sin(angle);
|
||||||
|
len = (float) Math.sqrt(u * u + v * v);
|
||||||
|
u /= len;
|
||||||
|
v /= len;
|
||||||
|
gl.glNormal3f(v, -u, 0.0f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), -width * 0.5f);
|
||||||
|
gl.glNormal3f((float) Math.cos(angle), (float) Math.sin(angle), 0.0f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + 2 * da), r2 * (float) Math.sin(angle + 2 * da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float) Math.cos(angle + 2 * da), r2 * (float) Math.sin(angle + 2 * da), -width * 0.5f);
|
||||||
|
u = r1 * (float) Math.cos(angle + 3 * da) - r2 * (float) Math.cos(angle + 2 * da);
|
||||||
|
v = r1 * (float) Math.sin(angle + 3 * da) - r2 * (float) Math.sin(angle + 2 * da);
|
||||||
|
gl.glNormal3f(v, -u, 0.0f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), -width * 0.5f);
|
||||||
|
gl.glNormal3f((float) Math.cos(angle), (float) Math.sin(angle), 0.0f);
|
||||||
|
}
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(0), r1 * (float) Math.sin(0), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float) Math.cos(0), r1 * (float) Math.sin(0), -width * 0.5f);
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||||
|
|
||||||
|
/* draw inside radius cylinder */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i <= teeth; i++) {
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glNormal3f(-(float) Math.cos(angle), -(float) Math.sin(angle), 0.0f);
|
||||||
|
gl.glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods required for the implementation of MouseListener
|
||||||
|
public void mouseEntered(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseExited(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
prevMouseX = e.getX();
|
||||||
|
prevMouseY = e.getY();
|
||||||
|
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||||
|
mouseRButtonDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||||
|
mouseRButtonDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods required for the implementation of MouseMotionListener
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
int x = e.getX();
|
||||||
|
int y = e.getY();
|
||||||
|
Dimension size = e.getComponent().getSize();
|
||||||
|
|
||||||
|
float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) size.width);
|
||||||
|
float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) size.height);
|
||||||
|
|
||||||
|
prevMouseX = x;
|
||||||
|
prevMouseY = y;
|
||||||
|
|
||||||
|
view_rotx += thetaX;
|
||||||
|
view_roty += thetaY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseMoved(MouseEvent e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
337
src/cad/Gears.java
Normal file
337
src/cad/Gears.java
Normal file
|
|
@ -0,0 +1,337 @@
|
||||||
|
package cad;
|
||||||
|
|
||||||
|
import com.jogamp.opengl.util.Animator;
|
||||||
|
|
||||||
|
import javax.media.opengl.GL2;
|
||||||
|
import javax.media.opengl.GLAutoDrawable;
|
||||||
|
import javax.media.opengl.GLEventListener;
|
||||||
|
import javax.media.opengl.awt.AWTGLAutoDrawable;
|
||||||
|
import javax.media.opengl.awt.GLCanvas;
|
||||||
|
import javax.media.opengl.awt.GLJPanel;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.awt.event.MouseMotionListener;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gears.java <BR>
|
||||||
|
* author: Brian Paul (converted to Java by Ron Cemer and Sven Goethel) <P>
|
||||||
|
*
|
||||||
|
* This version is equal to Brian Paul's version 1.2 1999/10/21
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Gears implements GLEventListener, MouseListener, MouseMotionListener {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Frame frame = new Frame("Gear Demo");
|
||||||
|
GLCanvas canvas = new GLCanvas();
|
||||||
|
|
||||||
|
final Gears gears = new Gears();
|
||||||
|
canvas.addGLEventListener(gears);
|
||||||
|
|
||||||
|
frame.add(canvas);
|
||||||
|
frame.setSize(300, 300);
|
||||||
|
final Animator animator = new Animator(canvas);
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
// Run this on another thread than the AWT event queue to
|
||||||
|
// make sure the call to Animator.stop() completes before
|
||||||
|
// exiting
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
animator.stop();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
frame.setVisible(true);
|
||||||
|
animator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
|
||||||
|
private int gear1, gear2, gear3;
|
||||||
|
private float angle = 0.0f;
|
||||||
|
|
||||||
|
private int prevMouseX, prevMouseY;
|
||||||
|
private boolean mouseRButtonDown = false;
|
||||||
|
|
||||||
|
public void init(GLAutoDrawable drawable) {
|
||||||
|
// Use debug pipeline
|
||||||
|
// drawable.setGL(new DebugGL(drawable.getGL()));
|
||||||
|
|
||||||
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
|
|
||||||
|
System.err.println("INIT GL IS: " + gl.getClass().getName());
|
||||||
|
|
||||||
|
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
|
||||||
|
|
||||||
|
gl.setSwapInterval(1);
|
||||||
|
|
||||||
|
float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f };
|
||||||
|
float red[] = { 0.8f, 0.1f, 0.0f, 1.0f };
|
||||||
|
float green[] = { 0.0f, 0.8f, 0.2f, 1.0f };
|
||||||
|
float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f };
|
||||||
|
|
||||||
|
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos, 0);
|
||||||
|
gl.glEnable(GL2.GL_CULL_FACE);
|
||||||
|
gl.glEnable(GL2.GL_LIGHTING);
|
||||||
|
gl.glEnable(GL2.GL_LIGHT0);
|
||||||
|
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
/* make the gears */
|
||||||
|
gear1 = gl.glGenLists(1);
|
||||||
|
gl.glNewList(gear1, GL2.GL_COMPILE);
|
||||||
|
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, red, 0);
|
||||||
|
gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f);
|
||||||
|
gl.glEndList();
|
||||||
|
|
||||||
|
gear2 = gl.glGenLists(1);
|
||||||
|
gl.glNewList(gear2, GL2.GL_COMPILE);
|
||||||
|
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, green, 0);
|
||||||
|
gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f);
|
||||||
|
gl.glEndList();
|
||||||
|
|
||||||
|
gear3 = gl.glGenLists(1);
|
||||||
|
gl.glNewList(gear3, GL2.GL_COMPILE);
|
||||||
|
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||||
|
gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f);
|
||||||
|
gl.glEndList();
|
||||||
|
|
||||||
|
gl.glEnable(GL2.GL_NORMALIZE);
|
||||||
|
|
||||||
|
if (drawable instanceof AWTGLAutoDrawable) {
|
||||||
|
AWTGLAutoDrawable awtDrawable = (AWTGLAutoDrawable) drawable;
|
||||||
|
awtDrawable.addMouseListener(this);
|
||||||
|
awtDrawable.addMouseMotionListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||||
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
|
|
||||||
|
float h = (float)height / (float)width;
|
||||||
|
|
||||||
|
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||||
|
|
||||||
|
System.err.println("GL_VENDOR: " + gl.glGetString(GL2.GL_VENDOR));
|
||||||
|
System.err.println("GL_RENDERER: " + gl.glGetString(GL2.GL_RENDERER));
|
||||||
|
System.err.println("GL_VERSION: " + gl.glGetString(GL2.GL_VERSION));
|
||||||
|
gl.glLoadIdentity();
|
||||||
|
gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
|
||||||
|
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||||
|
gl.glLoadIdentity();
|
||||||
|
gl.glTranslatef(0.0f, 0.0f, -40.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose(GLAutoDrawable drawable) {
|
||||||
|
System.out.println("Gears.dispose: "+drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(GLAutoDrawable drawable) {
|
||||||
|
// Turn the gears' teeth
|
||||||
|
angle += 2.0f;
|
||||||
|
|
||||||
|
// Get the GL corresponding to the drawable we are animating
|
||||||
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
|
|
||||||
|
// Special handling for the case where the GLJPanel is translucent
|
||||||
|
// and wants to be composited with other Java 2D content
|
||||||
|
if ((drawable instanceof GLJPanel) &&
|
||||||
|
!((GLJPanel) drawable).isOpaque() &&
|
||||||
|
((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
|
||||||
|
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
|
||||||
|
} else {
|
||||||
|
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate the entire assembly of gears based on how the user
|
||||||
|
// dragged the mouse around
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
|
||||||
|
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
|
||||||
|
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Place the first gear and call its display list
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(-3.0f, -2.0f, 0.0f);
|
||||||
|
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glCallList(gear1);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
|
||||||
|
// Place the second gear and call its display list
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(3.1f, -2.0f, 0.0f);
|
||||||
|
gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glCallList(gear2);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
|
||||||
|
// Place the third gear and call its display list
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(-3.1f, 4.2f, 0.0f);
|
||||||
|
gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glCallList(gear3);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
|
||||||
|
// Remember that every push needs a pop; this one is paired with
|
||||||
|
// rotating the entire gear assembly
|
||||||
|
gl.glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
|
||||||
|
|
||||||
|
public static void gear(GL2 gl,
|
||||||
|
float inner_radius,
|
||||||
|
float outer_radius,
|
||||||
|
float width,
|
||||||
|
int teeth,
|
||||||
|
float tooth_depth)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
float r0, r1, r2;
|
||||||
|
float angle, da;
|
||||||
|
float u, v, len;
|
||||||
|
|
||||||
|
r0 = inner_radius;
|
||||||
|
r1 = outer_radius - tooth_depth / 2.0f;
|
||||||
|
r2 = outer_radius + tooth_depth / 2.0f;
|
||||||
|
|
||||||
|
da = 2.0f * (float) Math.PI / teeth / 4.0f;
|
||||||
|
|
||||||
|
gl.glShadeModel(GL2.GL_FLAT);
|
||||||
|
|
||||||
|
gl.glNormal3f(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
/* draw front face */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i <= teeth; i++)
|
||||||
|
{
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||||
|
if(i < teeth)
|
||||||
|
{
|
||||||
|
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw front sides of teeth */
|
||||||
|
gl.glBegin(GL2.GL_QUADS);
|
||||||
|
for (i = 0; i < teeth; i++)
|
||||||
|
{
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + 2.0f * da), r2 * (float)Math.sin(angle + 2.0f * da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw back face */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i <= teeth; i++)
|
||||||
|
{
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw back sides of teeth */
|
||||||
|
gl.glBegin(GL2.GL_QUADS);
|
||||||
|
for (i = 0; i < teeth; i++)
|
||||||
|
{
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
/* draw outward faces of teeth */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i < teeth; i++)
|
||||||
|
{
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||||
|
u = r2 * (float)Math.cos(angle + da) - r1 * (float)Math.cos(angle);
|
||||||
|
v = r2 * (float)Math.sin(angle + da) - r1 * (float)Math.sin(angle);
|
||||||
|
len = (float)Math.sqrt(u * u + v * v);
|
||||||
|
u /= len;
|
||||||
|
v /= len;
|
||||||
|
gl.glNormal3f(v, -u, 0.0f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
|
||||||
|
gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
|
||||||
|
u = r1 * (float)Math.cos(angle + 3 * da) - r2 * (float)Math.cos(angle + 2 * da);
|
||||||
|
v = r1 * (float)Math.sin(angle + 3 * da) - r2 * (float)Math.sin(angle + 2 * da);
|
||||||
|
gl.glNormal3f(v, -u, 0.0f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||||
|
gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
|
||||||
|
}
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), width * 0.5f);
|
||||||
|
gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), -width * 0.5f);
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||||
|
|
||||||
|
/* draw inside radius cylinder */
|
||||||
|
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||||
|
for (i = 0; i <= teeth; i++)
|
||||||
|
{
|
||||||
|
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||||
|
gl.glNormal3f(-(float)Math.cos(angle), -(float)Math.sin(angle), 0.0f);
|
||||||
|
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||||
|
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||||
|
}
|
||||||
|
gl.glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods required for the implementation of MouseListener
|
||||||
|
public void mouseEntered(MouseEvent e) {}
|
||||||
|
public void mouseExited(MouseEvent e) {}
|
||||||
|
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
prevMouseX = e.getX();
|
||||||
|
prevMouseY = e.getY();
|
||||||
|
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||||
|
mouseRButtonDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||||
|
mouseRButtonDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseClicked(MouseEvent e) {}
|
||||||
|
|
||||||
|
// Methods required for the implementation of MouseMotionListener
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
int x = e.getX();
|
||||||
|
int y = e.getY();
|
||||||
|
Dimension size = e.getComponent().getSize();
|
||||||
|
|
||||||
|
float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)size.width);
|
||||||
|
float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)size.height);
|
||||||
|
|
||||||
|
prevMouseX = x;
|
||||||
|
prevMouseY = y;
|
||||||
|
|
||||||
|
view_rotx += thetaX;
|
||||||
|
view_roty += thetaY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseMoved(MouseEvent e) {}
|
||||||
|
}
|
||||||
60
src/cad/JOGL2NewtDemo.java
Normal file
60
src/cad/JOGL2NewtDemo.java
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package cad;
|
||||||
|
|
||||||
|
import javax.media.opengl.GLCapabilities;
|
||||||
|
import javax.media.opengl.GLProfile;
|
||||||
|
import com.jogamp.newt.event.WindowAdapter;
|
||||||
|
import com.jogamp.newt.event.WindowEvent;
|
||||||
|
import com.jogamp.newt.opengl.GLWindow;
|
||||||
|
import com.jogamp.opengl.util.FPSAnimator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A program that draws with JOGL in a NEWT GLWindow.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JOGL2NewtDemo {
|
||||||
|
private static String TITLE = "JOGL 2 with NEWT"; // window's title
|
||||||
|
private static final int WINDOW_WIDTH = 640; // width of the drawable
|
||||||
|
private static final int WINDOW_HEIGHT = 480; // height of the drawable
|
||||||
|
private static final int FPS = 60; // animator's target frames per second
|
||||||
|
|
||||||
|
static {
|
||||||
|
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entry main() method.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Get the default OpenGL profile, reflecting the best for your running platform
|
||||||
|
GLProfile glp = GLProfile.getDefault();
|
||||||
|
// Specifies a set of OpenGL capabilities, based on your profile.
|
||||||
|
GLCapabilities caps = new GLCapabilities(glp);
|
||||||
|
// Create the OpenGL rendering canvas
|
||||||
|
GLWindow window = GLWindow.create(caps);
|
||||||
|
|
||||||
|
// Create a animator that drives canvas' display() at the specified FPS.
|
||||||
|
final FPSAnimator animator = new FPSAnimator(window, FPS, true);
|
||||||
|
|
||||||
|
window.addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowDestroyNotify(WindowEvent arg0) {
|
||||||
|
// Use a dedicate thread to run the stop() to ensure that the
|
||||||
|
// animator stops before program exits.
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (animator.isStarted())
|
||||||
|
animator.stop(); // stop the animator loop
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addGLEventListener(new JOGL2Renderer());
|
||||||
|
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
|
window.setTitle(TITLE);
|
||||||
|
window.setVisible(true);
|
||||||
|
animator.start(); // start the animator loop
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/cad/JOGL2Renderer.java
Normal file
60
src/cad/JOGL2Renderer.java
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package cad;
|
||||||
|
|
||||||
|
import javax.media.opengl.GL;
|
||||||
|
import javax.media.opengl.GL2;
|
||||||
|
import javax.media.opengl.GLAutoDrawable;
|
||||||
|
import javax.media.opengl.GLEventListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class handles the OpenGL events to render graphics.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JOGL2Renderer implements GLEventListener {
|
||||||
|
private double theta = 0.0f; // rotational angle
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(GLAutoDrawable drawable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose(GLAutoDrawable drawable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called back by the drawable to render OpenGL graphics
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void display(GLAutoDrawable drawable) {
|
||||||
|
GL2 gl = drawable.getGL().getGL2(); // get the OpenGL graphics context
|
||||||
|
|
||||||
|
gl.glClear(GL.GL_COLOR_BUFFER_BIT); // clear background
|
||||||
|
gl.glLoadIdentity(); // reset the model-view matrix
|
||||||
|
|
||||||
|
// Rendering code - draw a triangle
|
||||||
|
float sine = (float)Math.sin(theta);
|
||||||
|
float cosine = (float)Math.cos(theta);
|
||||||
|
gl.glBegin(GL.GL_TRIANGLES);
|
||||||
|
gl.glColor3f(1, 0, 0);
|
||||||
|
gl.glVertex2d(-cosine, -cosine);
|
||||||
|
gl.glColor3f(0, 1, 0);
|
||||||
|
gl.glVertex2d(0, cosine);
|
||||||
|
gl.glColor3f(0, 0, 1);
|
||||||
|
gl.glVertex2d(sine, -sine);
|
||||||
|
gl.glEnd();
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the rotation angle after each frame refresh
|
||||||
|
*/
|
||||||
|
private void update() {
|
||||||
|
theta += 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*... Other methods leave blank ...*/
|
||||||
|
}
|
||||||
22
src/cad/fx/App.java
Normal file
22
src/cad/fx/App.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
public class App extends Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.setProperty("prism.dirtyopts", "false");
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) throws Exception {
|
||||||
|
Scene scene = new Scene(FXMLLoader.load(AppCtrl.class.getResource("app.fxml")), 1024, 1100);
|
||||||
|
primaryStage.setTitle("Solid CAD");
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/cad/fx/AppCtrl.java
Normal file
49
src/cad/fx/AppCtrl.java
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import cad.fx.viewer.Viewer3D;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
|
public class AppCtrl implements Initializable {
|
||||||
|
|
||||||
|
private final CadContext cadContext = new CadContext();
|
||||||
|
|
||||||
|
public Viewer3D viewer;
|
||||||
|
public Button beginSketching;
|
||||||
|
public Button endSketching;
|
||||||
|
public Button pad;
|
||||||
|
public Button cut;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
Group content = new Group(getInitObject());
|
||||||
|
viewer.setContent(content);
|
||||||
|
beginSketching.setOnAction(event -> {
|
||||||
|
cadContext.beginSketching();
|
||||||
|
});
|
||||||
|
endSketching.setOnAction(event -> {
|
||||||
|
cadContext.endSketching();
|
||||||
|
});
|
||||||
|
pad.setOnAction(event -> {
|
||||||
|
cadContext.pad(50);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node getInitObject() {
|
||||||
|
|
||||||
|
Surface square = Utils3D.createSquare(100);
|
||||||
|
// square = square.flip();
|
||||||
|
return new CSGNode(Utils3D.getMesh(singletonList(square)), cadContext);
|
||||||
|
|
||||||
|
//
|
||||||
|
// CSG init = new Cube(100).toCSG().difference(new Cylinder(30, 100, 10).toCSG());
|
||||||
|
// return new CSGNode(Utils3D.getFXMesh(init), cadContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/cad/fx/CSGMesh.java
Normal file
12
src/cad/fx/CSGMesh.java
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import eu.mihosoft.vrl.v3d.Polygon;
|
||||||
|
import gnu.trove.map.TIntObjectMap;
|
||||||
|
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||||
|
import javafx.scene.shape.TriangleMesh;
|
||||||
|
|
||||||
|
public class CSGMesh extends TriangleMesh {
|
||||||
|
|
||||||
|
public final TIntObjectMap<Surface> polygons = new TIntObjectHashMap<>();
|
||||||
|
|
||||||
|
}
|
||||||
41
src/cad/fx/CSGNode.java
Normal file
41
src/cad/fx/CSGNode.java
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import eu.mihosoft.vrl.v3d.CSG;
|
||||||
|
import eu.mihosoft.vrl.v3d.Polygon;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.shape.MeshView;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CSGNode extends MeshView {
|
||||||
|
|
||||||
|
private final CadContext context;
|
||||||
|
|
||||||
|
public CSGNode(CSGMesh mesh, CadContext context) {
|
||||||
|
super(mesh);
|
||||||
|
this.context = context;
|
||||||
|
setMaterial(Utils3D.DEFAULT_MATERIAL);
|
||||||
|
setOnMouseClicked(e -> {
|
||||||
|
context.clickOnNode(this, e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void highlight(Polygon poly) {
|
||||||
|
System.out.println(poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Map<Surface, Sketch> sketches = new HashMap<>();
|
||||||
|
|
||||||
|
public Sketch getSketch(Surface surface) {
|
||||||
|
Sketch sketch = sketches.get(surface);
|
||||||
|
if (sketch == null) {
|
||||||
|
sketch = new Sketch(surface);
|
||||||
|
((Group) getParent()).getChildren().add(sketch.drawLayer);
|
||||||
|
sketches.put(surface, sketch);
|
||||||
|
}
|
||||||
|
return sketch;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
85
src/cad/fx/CadContext.java
Normal file
85
src/cad/fx/CadContext.java
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import cad.math.Vector;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.input.PickResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CadContext {
|
||||||
|
|
||||||
|
public Sketcher sketcher;
|
||||||
|
public Selection selection;
|
||||||
|
|
||||||
|
public void clickOnNode(CSGNode csgNode, MouseEvent e) {
|
||||||
|
PickResult pickResult = e.getPickResult();
|
||||||
|
int face = pickResult.getIntersectedFace();
|
||||||
|
CSGMesh csgMesh = (CSGMesh) csgNode.getMesh();
|
||||||
|
Surface surface = csgMesh.polygons.get(face);
|
||||||
|
System.out.println(surface);
|
||||||
|
if (surface != null) {
|
||||||
|
if (selection != null) {
|
||||||
|
boolean isSameNode = selection.sameTo(csgNode, surface);
|
||||||
|
if (sketcher == null && !isSameNode) {
|
||||||
|
selection = new Selection(csgNode, surface);
|
||||||
|
}
|
||||||
|
if (sketcher != null && isSameNode) {
|
||||||
|
sketcher.addPoint(pickResult.getIntersectedPoint());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sketcher == null) {
|
||||||
|
selection = new Selection(csgNode, surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beginSketching() {
|
||||||
|
if (sketcher != null || selection == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sketcher = new Sketcher(selection.csgNode.getSketch(selection.surface));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endSketching() {
|
||||||
|
if (sketcher == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sketcher.commitOperation();
|
||||||
|
sketcher = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pad(double height) {
|
||||||
|
if (selection == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sketch sketch = selection.csgNode.getSketch(selection.surface);
|
||||||
|
for (List<Vector> polygon : sketch.polygons) {
|
||||||
|
if (polygon.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vector dir = sketch.owner.normal.scale(height);
|
||||||
|
|
||||||
|
List<Surface> extruded = Surface.extrude(sketch.owner, dir);
|
||||||
|
|
||||||
|
// CSG pad = Extrude.points(dir, polygon);
|
||||||
|
sketch.drawLayer.getChildren().addAll(new CSGNode(Utils3D.getMesh(extruded), this)); // fixme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Selection {
|
||||||
|
|
||||||
|
public final CSGNode csgNode;
|
||||||
|
public final Surface surface;
|
||||||
|
|
||||||
|
public Selection(CSGNode csgNode, Surface surface) {
|
||||||
|
this.csgNode = csgNode;
|
||||||
|
this.surface = surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean sameTo(CSGNode csgNode, Surface surface) {
|
||||||
|
return this.csgNode.equals(csgNode) && this.surface.equals(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/cad/fx/Sketch.java
Normal file
18
src/cad/fx/Sketch.java
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import cad.math.Vector;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Sketch {
|
||||||
|
|
||||||
|
public final Surface owner;
|
||||||
|
public final List<List<Vector>> polygons = new ArrayList<>();
|
||||||
|
public final Group drawLayer = new Group();
|
||||||
|
|
||||||
|
public Sketch(Surface owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/cad/fx/Sketcher.java
Normal file
33
src/cad/fx/Sketcher.java
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import cad.math.Vector;
|
||||||
|
import eu.mihosoft.vrl.v3d.Vector3d;
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.shape.Sphere;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Sketcher {
|
||||||
|
|
||||||
|
public final Sketch sketch;
|
||||||
|
|
||||||
|
public Sketcher(Sketch sketch) {
|
||||||
|
this.sketch = sketch;
|
||||||
|
if (sketch.polygons.isEmpty()) {
|
||||||
|
sketch.polygons.add(new ArrayList<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPoint(Point3D point) {
|
||||||
|
sketch.polygons.get(sketch.polygons.size() - 1).add(new Vector(point.getX(), point.getY(), point.getZ()));
|
||||||
|
Sphere pt = new Sphere(1);
|
||||||
|
pt.setTranslateX(point.getX());
|
||||||
|
pt.setTranslateY(point.getY());
|
||||||
|
pt.setTranslateZ(point.getZ());
|
||||||
|
sketch.drawLayer.getChildren().addAll(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commitOperation() {
|
||||||
|
sketch.polygons.add(new ArrayList<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
172
src/cad/fx/Surface.java
Normal file
172
src/cad/fx/Surface.java
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import cad.math.HMath;
|
||||||
|
import cad.math.Matrix;
|
||||||
|
import cad.math.Vector;
|
||||||
|
import org.poly2tri.Poly2Tri;
|
||||||
|
import org.poly2tri.geometry.polygon.Polygon;
|
||||||
|
import org.poly2tri.geometry.polygon.PolygonPoint;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
|
public class Surface {
|
||||||
|
|
||||||
|
public final Vector normal;
|
||||||
|
public final List<Vector> shell;
|
||||||
|
public final List<List<Vector>> holes;
|
||||||
|
|
||||||
|
private List<Vector[]> triangles;
|
||||||
|
|
||||||
|
public Surface(List<Vector> shell) {
|
||||||
|
this(shell, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Surface(List<Vector> shell, List<List<Vector>> holes) {
|
||||||
|
this(normalOfCCWSeq(shell.get(0), shell.get(1), shell.get(2)), shell, holes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Surface(Vector normal, List<Vector> shell, List<List<Vector>> holes) {
|
||||||
|
this.normal = normal.normalize();
|
||||||
|
this.shell = shell;
|
||||||
|
this.holes = holes;
|
||||||
|
checkPolygon(shell);
|
||||||
|
for (List<Vector> hole : holes) {
|
||||||
|
if (hole.size() < 3) {
|
||||||
|
checkPolygon(hole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Surface fixCCW() {
|
||||||
|
if (!normal.slightlyEqualTo(normalOfCCWSeq(shell.get(0), shell.get(1), shell.get(2)))) {
|
||||||
|
List<Vector> shell = new ArrayList<>(this.shell);
|
||||||
|
Collections.reverse(shell);
|
||||||
|
return new Surface(normal, shell, holes);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Vector[] someBasis() {
|
||||||
|
Vector x = shell.get(1).minus(shell.get(0)).normalize();
|
||||||
|
Vector y = normal.cross(x).normalize();
|
||||||
|
return new Vector[] {x, y, normal};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPolygon(List<Vector> shell) {
|
||||||
|
if (shell.size() < 3) {
|
||||||
|
throw new IllegalArgumentException("Polygon should contain at least 3 point");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Vector[]> getTriangles() {
|
||||||
|
if (triangles == null) {
|
||||||
|
triangulate();
|
||||||
|
}
|
||||||
|
return triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triangulate() {
|
||||||
|
|
||||||
|
Matrix _3dTransformation = new Matrix(someBasis());
|
||||||
|
Matrix _2dTransformation = _3dTransformation.invert();
|
||||||
|
|
||||||
|
List<PolygonPoint> shellPoints = shell.stream()
|
||||||
|
.map(vector -> HMath.cross(_2dTransformation, vector))
|
||||||
|
.map(vector -> new PolygonPoint(vector.x, vector.y, vector.z))
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
|
Polygon polygon = new Polygon(shellPoints);
|
||||||
|
|
||||||
|
for (List<Vector> hole : holes) {
|
||||||
|
|
||||||
|
List<PolygonPoint> holePoints = hole.stream()
|
||||||
|
.map(vector -> HMath.cross(_2dTransformation, vector))
|
||||||
|
.map(vector -> new PolygonPoint(vector.x, vector.y, vector.z))
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
|
polygon.addHole(new Polygon(holePoints));
|
||||||
|
}
|
||||||
|
|
||||||
|
Poly2Tri.triangulate(polygon);
|
||||||
|
|
||||||
|
triangles = polygon.getTriangles().stream()
|
||||||
|
.map(tr ->
|
||||||
|
new Vector[]{
|
||||||
|
HMath.cross(_3dTransformation, new Vector(tr.points[0].getX(), tr.points[0].getY(), tr.points[0].getZ())),
|
||||||
|
HMath.cross(_3dTransformation, new Vector(tr.points[1].getX(), tr.points[1].getY(), tr.points[1].getZ())),
|
||||||
|
HMath.cross(_3dTransformation, new Vector(tr.points[2].getX(), tr.points[2].getY(), tr.points[2].getZ()))
|
||||||
|
})
|
||||||
|
.collect(Collectors.<Vector[]>toList());
|
||||||
|
|
||||||
|
setupNormal(triangles, normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setupNormal(List<Vector[]> triangles, Vector normal) {
|
||||||
|
|
||||||
|
for (Vector[] triangle : triangles) {
|
||||||
|
if (!normalOfCCWSeq(triangle[0], triangle[1], triangle[2]).slightlyEqualTo(normal)) {
|
||||||
|
reverse(triangle);
|
||||||
|
System.out.println("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector normalOfCCWSeq(Vector v0, Vector v1, Vector v2) {
|
||||||
|
return v1.minus(v0).cross(v2.minus(v0)).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void reverse(Vector[] triangle) {
|
||||||
|
Vector first = triangle[0];
|
||||||
|
triangle[0] = triangle[2];
|
||||||
|
triangle[2] = first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Surface flip() {
|
||||||
|
return new Surface(normal.negate(), shell, holes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Surface> extrude(Surface source, Vector target) {
|
||||||
|
|
||||||
|
double dotProduct = target.normalize().dot(source.normal);
|
||||||
|
if (dotProduct == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
if (dotProduct > 0) {
|
||||||
|
source = source.flip();
|
||||||
|
}
|
||||||
|
source = source.fixCCW();
|
||||||
|
|
||||||
|
List<Surface> surfaces = new ArrayList<>();
|
||||||
|
surfaces.add(source);
|
||||||
|
|
||||||
|
Surface lid = source.shift(target).flip();
|
||||||
|
surfaces.add(lid);
|
||||||
|
|
||||||
|
for (int i = 1; i < source.shell.size(); i++) {
|
||||||
|
Surface face = new Surface(Arrays.asList(
|
||||||
|
source.shell.get(i - 1),
|
||||||
|
source.shell.get(i),
|
||||||
|
lid.shell.get(i),
|
||||||
|
lid.shell.get(i - 1)
|
||||||
|
));
|
||||||
|
surfaces.add(face);
|
||||||
|
}
|
||||||
|
return surfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Surface shift(Vector target) {
|
||||||
|
List<Vector> shell = this.shell.stream().map(vector -> vector.plus(target)).collect(toList());
|
||||||
|
List<List<Vector>> holes = new ArrayList<>();
|
||||||
|
for (List<Vector> hole : this.holes) {
|
||||||
|
holes.add(hole.stream().map(vector -> vector.plus(target)).collect(toList()));
|
||||||
|
}
|
||||||
|
return new Surface(normal, shell, holes);
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/cad/fx/Test.java
Normal file
82
src/cad/fx/Test.java
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.canvas.Canvas;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.scene.shape.Line;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.poly2tri.Poly2Tri;
|
||||||
|
import org.poly2tri.geometry.polygon.Polygon;
|
||||||
|
import org.poly2tri.geometry.polygon.PolygonPoint;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Test extends Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.setProperty("prism.dirtyopts", "false");
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) throws Exception {
|
||||||
|
Pane pane = new Pane();
|
||||||
|
Scene scene = new Scene(pane, 600, 600);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Polygon polygon = new Polygon(Arrays.asList(
|
||||||
|
new PolygonPoint(0, 0),
|
||||||
|
// new PolygonPoint(200, 100),
|
||||||
|
new PolygonPoint(400, 0),
|
||||||
|
new PolygonPoint(400, 400),
|
||||||
|
new PolygonPoint(0, 400)
|
||||||
|
));
|
||||||
|
|
||||||
|
Polygon hole = new Polygon(Arrays.asList(
|
||||||
|
new PolygonPoint(50, 50),
|
||||||
|
new PolygonPoint(50, 100),
|
||||||
|
new PolygonPoint(100, 100),
|
||||||
|
new PolygonPoint(100, 50)
|
||||||
|
));
|
||||||
|
|
||||||
|
polygon.addHole(hole);
|
||||||
|
|
||||||
|
Poly2Tri.triangulate(polygon);
|
||||||
|
|
||||||
|
|
||||||
|
for (DelaunayTriangle triangle : polygon.getTriangles()) {
|
||||||
|
show(pane, Arrays.asList(triangle.points));
|
||||||
|
}
|
||||||
|
|
||||||
|
pane.getTransforms().add(new Translate(10, 10));
|
||||||
|
show(pane, polygon);
|
||||||
|
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show(Pane pane, Polygon polygon) {
|
||||||
|
show(pane, polygon.getPoints());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show(Pane pane, List<TriangulationPoint> points) {
|
||||||
|
|
||||||
|
TriangulationPoint first = points.get(0);
|
||||||
|
TriangulationPoint prev = first;
|
||||||
|
for (TriangulationPoint point : points.subList(1, points.size())) {
|
||||||
|
pane.getChildren().addAll(new Line(prev.getX(), prev.getY(), point.getX(), point.getY()));
|
||||||
|
prev = point;
|
||||||
|
}
|
||||||
|
pane.getChildren().addAll(new Line(prev.getX(), prev.getY(), first.getX(), first.getY()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
174
src/cad/fx/Utils3D.java
Normal file
174
src/cad/fx/Utils3D.java
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
package cad.fx;
|
||||||
|
|
||||||
|
import cad.math.Vector;
|
||||||
|
import eu.mihosoft.vrl.v3d.CSG;
|
||||||
|
import eu.mihosoft.vrl.v3d.MeshContainer;
|
||||||
|
import eu.mihosoft.vrl.v3d.Polygon;
|
||||||
|
import eu.mihosoft.vrl.v3d.Vector3d;
|
||||||
|
import eu.mihosoft.vrl.v3d.Vertex;
|
||||||
|
import eu.mihosoft.vrl.v3d.ext.org.poly2tri.PolygonUtil;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.PhongMaterial;
|
||||||
|
import javafx.scene.shape.TriangleMesh;
|
||||||
|
import org.poly2tri.Poly2Tri;
|
||||||
|
import org.poly2tri.geometry.polygon.PolygonPoint;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Utils3D {
|
||||||
|
|
||||||
|
public static final PhongMaterial DEFAULT_MATERIAL = new PhongMaterial();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// DEFAULT_MATERIAL.setDiffuseColor(Color.LIGHTBLUE);
|
||||||
|
// DEFAULT_MATERIAL.setSpecularColor(Color.WHITE);
|
||||||
|
|
||||||
|
DEFAULT_MATERIAL.setDiffuseColor(Color.LIGHTSTEELBLUE);
|
||||||
|
DEFAULT_MATERIAL.setSpecularColor(Color.LIGHTBLUE);
|
||||||
|
|
||||||
|
// DEFAULT_MATERIAL.setDiffuseMap(new Image(Utils3D.class.getResource("tex.png").toExternalForm()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CSGMesh getMesh(List<Surface> surfaces) {
|
||||||
|
|
||||||
|
CSGMesh mesh = new CSGMesh();
|
||||||
|
|
||||||
|
int faceCounter = 0;
|
||||||
|
|
||||||
|
for (Surface surface : surfaces) {
|
||||||
|
|
||||||
|
|
||||||
|
for (Vector[] triangle : surface.getTriangles()) {
|
||||||
|
|
||||||
|
|
||||||
|
mesh.getPoints().addAll(
|
||||||
|
(float) triangle[0].x,
|
||||||
|
(float) triangle[0].y,
|
||||||
|
(float) triangle[0].z
|
||||||
|
);
|
||||||
|
|
||||||
|
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||||
|
mesh.getTexCoords().addAll(0);
|
||||||
|
|
||||||
|
|
||||||
|
mesh.getPoints().addAll(
|
||||||
|
(float) triangle[1].x,
|
||||||
|
(float) triangle[1].y,
|
||||||
|
(float) triangle[1].z
|
||||||
|
);
|
||||||
|
|
||||||
|
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||||
|
mesh.getTexCoords().addAll(0);
|
||||||
|
|
||||||
|
mesh.getPoints().addAll(
|
||||||
|
(float) triangle[2].x,
|
||||||
|
(float) triangle[2].y,
|
||||||
|
(float) triangle[2].z
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||||
|
mesh.getTexCoords().addAll(0);
|
||||||
|
|
||||||
|
int counter = faceCounter * 3;
|
||||||
|
mesh.getFaces().addAll(
|
||||||
|
counter, // first vertex
|
||||||
|
0, // texture (not covered)
|
||||||
|
counter + 1, // second vertex
|
||||||
|
0, // texture (not covered)
|
||||||
|
counter + 2, // third vertex
|
||||||
|
0 // texture (not covered)
|
||||||
|
);
|
||||||
|
mesh.polygons.put(faceCounter, surface);
|
||||||
|
++faceCounter;
|
||||||
|
|
||||||
|
} // end if #verts >= 3
|
||||||
|
|
||||||
|
} // end for polygon
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CSGMesh getFXMesh(List<DelaunayTriangle> triangles) {
|
||||||
|
|
||||||
|
CSGMesh mesh = new CSGMesh();
|
||||||
|
|
||||||
|
int faceCounter = 0;
|
||||||
|
|
||||||
|
for (DelaunayTriangle p : triangles) {
|
||||||
|
|
||||||
|
|
||||||
|
TriangulationPoint firstVertex = p.points[0];
|
||||||
|
|
||||||
|
mesh.getPoints().addAll(
|
||||||
|
p.points[2].getXf(),
|
||||||
|
p.points[2].getYf(),
|
||||||
|
p.points[2].getZf()
|
||||||
|
);
|
||||||
|
|
||||||
|
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||||
|
mesh.getTexCoords().addAll(0);
|
||||||
|
|
||||||
|
mesh.getPoints().addAll(
|
||||||
|
p.points[1].getXf(),
|
||||||
|
p.points[1].getYf(),
|
||||||
|
p.points[1].getZf()
|
||||||
|
);
|
||||||
|
|
||||||
|
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||||
|
mesh.getTexCoords().addAll(0);
|
||||||
|
|
||||||
|
mesh.getPoints().addAll(
|
||||||
|
p.points[0].getXf(),
|
||||||
|
p.points[0].getYf(),
|
||||||
|
p.points[0].getZf()
|
||||||
|
);
|
||||||
|
|
||||||
|
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||||
|
mesh.getTexCoords().addAll(0);
|
||||||
|
|
||||||
|
int counter = faceCounter * 3;
|
||||||
|
mesh.getFaces().addAll(
|
||||||
|
counter, // first vertex
|
||||||
|
0, // texture (not covered)
|
||||||
|
counter + 1, // second vertex
|
||||||
|
0, // texture (not covered)
|
||||||
|
counter + 2, // third vertex
|
||||||
|
0 // texture (not covered)
|
||||||
|
);
|
||||||
|
// mesh.polygons.put(faceCounter, p);
|
||||||
|
++faceCounter;
|
||||||
|
|
||||||
|
} // end for polygon
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Surface createSquare(double width) {
|
||||||
|
|
||||||
|
width /= 2;
|
||||||
|
|
||||||
|
List<Vector> shell = Arrays.asList(
|
||||||
|
new Vector(-width, -width),
|
||||||
|
new Vector(width, -width),
|
||||||
|
new Vector(width, width, 0),
|
||||||
|
new Vector(-width, width, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// width /= 3;
|
||||||
|
// org.poly2tri.geometry.polygon.Polygon hole = new org.poly2tri.geometry.polygon.Polygon(Arrays.asList(
|
||||||
|
// new PolygonPoint(-width, -width),
|
||||||
|
// new PolygonPoint(width, -width),
|
||||||
|
// new PolygonPoint(width, width, 100),
|
||||||
|
// new PolygonPoint(-width, width, 100)
|
||||||
|
// ));
|
||||||
|
//
|
||||||
|
// polygon.addHole(hole);
|
||||||
|
|
||||||
|
return new Surface(shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/cad/fx/app.fxml
Normal file
24
src/cad/fx/app.fxml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import cad.fx.viewer.* ?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.ToolBar?>
|
||||||
|
<?import javafx.scene.layout.Region?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<VBox xmlns:fx="fx" fx:controller="cad.fx.AppCtrl">
|
||||||
|
|
||||||
|
<ToolBar>
|
||||||
|
<Region styleClass="spacer"/>
|
||||||
|
<HBox styleClass="segmented-button-bar">
|
||||||
|
<Button text="Begin" fx:id="beginSketching"/>
|
||||||
|
<Button text="End" fx:id="endSketching"/>
|
||||||
|
<Button text="Pad" fx:id="pad"/>
|
||||||
|
<Button text="Cut" fx:id="cut"/>
|
||||||
|
</HBox>
|
||||||
|
</ToolBar>
|
||||||
|
|
||||||
|
<Viewer3D fx:id="viewer"/>
|
||||||
|
|
||||||
|
</VBox>
|
||||||
BIN
src/cad/fx/tex.png
Normal file
BIN
src/cad/fx/tex.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 B |
304
src/cad/fx/viewer/Viewer3D.java
Normal file
304
src/cad/fx/viewer/Viewer3D.java
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011, 2013 Oracle and/or its affiliates.
|
||||||
|
* All rights reserved. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* This file is available and licensed under the following license:
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the distribution.
|
||||||
|
* - Neither the name of Oracle nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cad.fx.viewer;
|
||||||
|
|
||||||
|
import javafx.animation.Timeline;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.*;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.input.ScrollEvent;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.PhongMaterial;
|
||||||
|
import javafx.scene.shape.Box;
|
||||||
|
import javafx.scene.shape.Sphere;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
public class Viewer3D extends SubScene {
|
||||||
|
|
||||||
|
final Group root = new Group();
|
||||||
|
final Group axisGroup = new Group();
|
||||||
|
public final Xform world = new Xform();
|
||||||
|
final PerspectiveCamera camera = new PerspectiveCamera(true);
|
||||||
|
final Xform cameraXform = new Xform();
|
||||||
|
final Xform cameraXform2 = new Xform();
|
||||||
|
final Xform cameraXform3 = new Xform();
|
||||||
|
final double cameraDistance = 450;
|
||||||
|
final Xform modelGroup = new Xform();
|
||||||
|
public final Xform modelXform = new Xform();
|
||||||
|
private Timeline timeline;
|
||||||
|
boolean timelinePlaying = false;
|
||||||
|
double ONE_FRAME = 1.0 / 24.0;
|
||||||
|
double DELTA_MULTIPLIER = 200.0;
|
||||||
|
double CONTROL_MULTIPLIER = 0.1;
|
||||||
|
double SHIFT_MULTIPLIER = 0.1;
|
||||||
|
double ALT_MULTIPLIER = 0.5;
|
||||||
|
double mousePosX;
|
||||||
|
double mousePosY;
|
||||||
|
double mouseOldX;
|
||||||
|
double mouseOldY;
|
||||||
|
double mouseDeltaX;
|
||||||
|
double mouseDeltaY;
|
||||||
|
|
||||||
|
public Viewer3D() {
|
||||||
|
super(new Group(), 1024, 768, true, SceneAntialiasing.DISABLED);
|
||||||
|
((Group)getRoot()).getChildren().add(world);
|
||||||
|
buildCamera();
|
||||||
|
buildAxes();
|
||||||
|
modelGroup.getChildren().add(modelXform);
|
||||||
|
world.getChildren().addAll(modelGroup);
|
||||||
|
world.getTransforms().add(new Rotate(180, new Point3D(1,0,0))); //fix Y-axis
|
||||||
|
|
||||||
|
// scene = new SubScene();
|
||||||
|
setFill(Color.GREY);
|
||||||
|
handleKeyboard(this, world);
|
||||||
|
handleMouse(this, world);
|
||||||
|
setCamera(camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(Node content) {
|
||||||
|
modelXform.getChildren().setAll(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildCamera() {
|
||||||
|
root.getChildren().add(cameraXform);
|
||||||
|
cameraXform.getChildren().add(cameraXform2);
|
||||||
|
cameraXform2.getChildren().add(cameraXform3);
|
||||||
|
cameraXform3.getChildren().add(camera);
|
||||||
|
// cameraXform3.setRotateZ(180.0);
|
||||||
|
|
||||||
|
camera.setNearClip(0.1);
|
||||||
|
camera.setFarClip(10000.0);
|
||||||
|
camera.setTranslateZ(-cameraDistance);
|
||||||
|
cameraXform.ry.setAngle(315.0);
|
||||||
|
cameraXform.rx.setAngle(-25);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildAxes() {
|
||||||
|
final PhongMaterial redMaterial = new PhongMaterial();
|
||||||
|
redMaterial.setDiffuseColor(Color.DARKRED);
|
||||||
|
redMaterial.setSpecularColor(Color.RED);
|
||||||
|
|
||||||
|
final PhongMaterial greenMaterial = new PhongMaterial();
|
||||||
|
greenMaterial.setDiffuseColor(Color.DARKGREEN);
|
||||||
|
greenMaterial.setSpecularColor(Color.GREEN);
|
||||||
|
|
||||||
|
final PhongMaterial blueMaterial = new PhongMaterial();
|
||||||
|
blueMaterial.setDiffuseColor(Color.DARKBLUE);
|
||||||
|
blueMaterial.setSpecularColor(Color.BLUE);
|
||||||
|
|
||||||
|
|
||||||
|
Sphere xArrow = new Sphere(1);
|
||||||
|
Sphere yArrow = new Sphere(1);
|
||||||
|
Sphere zArrow = new Sphere(1);
|
||||||
|
|
||||||
|
xArrow.setTranslateX(120);
|
||||||
|
yArrow.setTranslateY(120);
|
||||||
|
zArrow.setTranslateZ(120);
|
||||||
|
|
||||||
|
double axisWidth = 0.5;
|
||||||
|
final Box xAxis = new Box(240.0, axisWidth, axisWidth);
|
||||||
|
final Box yAxis = new Box(axisWidth, 240.0, axisWidth);
|
||||||
|
final Box zAxis = new Box(axisWidth, axisWidth, 240.0);
|
||||||
|
|
||||||
|
xAxis.setMaterial(redMaterial);
|
||||||
|
yAxis.setMaterial(greenMaterial);
|
||||||
|
zAxis.setMaterial(blueMaterial);
|
||||||
|
|
||||||
|
axisGroup.getChildren().addAll(xAxis, yAxis, zAxis, xArrow, yArrow, zArrow);
|
||||||
|
world.getChildren().addAll(axisGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
final double SCALE_DELTA = 1.1;
|
||||||
|
private void handleMouse(SubScene scene, final Node root) {
|
||||||
|
scene.setOnScroll(new EventHandler<ScrollEvent>() {
|
||||||
|
public void handle(ScrollEvent event) {
|
||||||
|
event.consume();
|
||||||
|
if (event.getDeltaY() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
double scaleFactor = event.getDeltaY() > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||||
|
cameraXform.setScale(scaleFactor * cameraXform.s.getX());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(MouseEvent me) {
|
||||||
|
mousePosX = me.getSceneX();
|
||||||
|
mousePosY = me.getSceneY();
|
||||||
|
mouseOldX = me.getSceneX();
|
||||||
|
mouseOldY = me.getSceneY();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(MouseEvent me) {
|
||||||
|
mouseOldX = mousePosX;
|
||||||
|
mouseOldY = mousePosY;
|
||||||
|
mousePosX = me.getSceneX();
|
||||||
|
mousePosY = me.getSceneY();
|
||||||
|
mouseDeltaX = (mousePosX - mouseOldX);
|
||||||
|
mouseDeltaY = (mousePosY - mouseOldY);
|
||||||
|
|
||||||
|
double modifierFactor = 0.1;
|
||||||
|
|
||||||
|
if (me.isPrimaryButtonDown()) {
|
||||||
|
double modifier = 1.0;
|
||||||
|
if (me.isControlDown()) modifier = 0.1;
|
||||||
|
if (me.isShiftDown()) modifier = 10.0;
|
||||||
|
|
||||||
|
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0); // +
|
||||||
|
cameraXform.rx.setAngle(cameraXform.rx.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0); // -
|
||||||
|
// System.out.println(cameraXform.ry.getAngle() + ":" + cameraXform.rx.getAngle());
|
||||||
|
} else if (me.isSecondaryButtonDown()) {
|
||||||
|
double modifier = 1.0;
|
||||||
|
if (me.isControlDown()) modifier = 0.1;
|
||||||
|
if (me.isShiftDown()) modifier = 10.0;
|
||||||
|
|
||||||
|
double z = camera.getTranslateZ();
|
||||||
|
double newZ = z + mouseDeltaX * modifierFactor * modifier;
|
||||||
|
camera.setTranslateZ(newZ);
|
||||||
|
} else if (me.isMiddleButtonDown()) {
|
||||||
|
double modifier = 10.0;
|
||||||
|
if (me.isControlDown()) modifier = 0.1;
|
||||||
|
|
||||||
|
cameraXform2.t.setX(cameraXform2.t.getX() - mouseDeltaX * modifierFactor * modifier * 0.3); // -
|
||||||
|
cameraXform2.t.setY(cameraXform2.t.getY() - mouseDeltaY * modifierFactor * modifier * 0.3); // -
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleKeyboard(SubScene scene, final Node root) {
|
||||||
|
final boolean moveCamera = true;
|
||||||
|
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(KeyEvent event) {
|
||||||
|
Duration currentTime;
|
||||||
|
switch (event.getCode()) {
|
||||||
|
case Z:
|
||||||
|
if (event.isShiftDown()) {
|
||||||
|
cameraXform.ry.setAngle(0.0);
|
||||||
|
cameraXform.rx.setAngle(0.0);
|
||||||
|
camera.setTranslateZ(-300.0);
|
||||||
|
}
|
||||||
|
cameraXform2.t.setX(0.0);
|
||||||
|
cameraXform2.t.setY(0.0);
|
||||||
|
break;
|
||||||
|
case X:
|
||||||
|
if (event.isControlDown()) {
|
||||||
|
if (axisGroup.isVisible()) {
|
||||||
|
axisGroup.setVisible(false);
|
||||||
|
} else {
|
||||||
|
axisGroup.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S:
|
||||||
|
if (event.isControlDown()) {
|
||||||
|
if (modelGroup.isVisible()) {
|
||||||
|
modelGroup.setVisible(false);
|
||||||
|
} else {
|
||||||
|
modelGroup.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SPACE:
|
||||||
|
if (timelinePlaying) {
|
||||||
|
timeline.pause();
|
||||||
|
timelinePlaying = false;
|
||||||
|
} else {
|
||||||
|
timeline.play();
|
||||||
|
timelinePlaying = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UP:
|
||||||
|
if (event.isControlDown() && event.isShiftDown()) {
|
||||||
|
cameraXform2.t.setY(cameraXform2.t.getY() - 10.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||||
|
cameraXform.rx.setAngle(cameraXform.rx.getAngle() - 10.0 * ALT_MULTIPLIER);
|
||||||
|
} else if (event.isControlDown()) {
|
||||||
|
cameraXform2.t.setY(cameraXform2.t.getY() - 1.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown()) {
|
||||||
|
cameraXform.rx.setAngle(cameraXform.rx.getAngle() - 2.0 * ALT_MULTIPLIER);
|
||||||
|
} else if (event.isShiftDown()) {
|
||||||
|
double z = camera.getTranslateZ();
|
||||||
|
double newZ = z + 5.0 * SHIFT_MULTIPLIER;
|
||||||
|
camera.setTranslateZ(newZ);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DOWN:
|
||||||
|
if (event.isControlDown() && event.isShiftDown()) {
|
||||||
|
cameraXform2.t.setY(cameraXform2.t.getY() + 10.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||||
|
cameraXform.rx.setAngle(cameraXform.rx.getAngle() + 10.0 * ALT_MULTIPLIER);
|
||||||
|
} else if (event.isControlDown()) {
|
||||||
|
cameraXform2.t.setY(cameraXform2.t.getY() + 1.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown()) {
|
||||||
|
cameraXform.rx.setAngle(cameraXform.rx.getAngle() + 2.0 * ALT_MULTIPLIER);
|
||||||
|
} else if (event.isShiftDown()) {
|
||||||
|
double z = camera.getTranslateZ();
|
||||||
|
double newZ = z - 5.0 * SHIFT_MULTIPLIER;
|
||||||
|
camera.setTranslateZ(newZ);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
if (event.isControlDown() && event.isShiftDown()) {
|
||||||
|
cameraXform2.t.setX(cameraXform2.t.getX() + 10.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||||
|
cameraXform.ry.setAngle(cameraXform.ry.getAngle() - 10.0 * ALT_MULTIPLIER);
|
||||||
|
} else if (event.isControlDown()) {
|
||||||
|
cameraXform2.t.setX(cameraXform2.t.getX() + 1.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown()) {
|
||||||
|
cameraXform.ry.setAngle(cameraXform.ry.getAngle() - 2.0 * ALT_MULTIPLIER);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LEFT:
|
||||||
|
if (event.isControlDown() && event.isShiftDown()) {
|
||||||
|
cameraXform2.t.setX(cameraXform2.t.getX() - 10.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||||
|
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + 10.0 * ALT_MULTIPLIER); // -
|
||||||
|
} else if (event.isControlDown()) {
|
||||||
|
cameraXform2.t.setX(cameraXform2.t.getX() - 1.0 * CONTROL_MULTIPLIER);
|
||||||
|
} else if (event.isAltDown()) {
|
||||||
|
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + 2.0 * ALT_MULTIPLIER); // -
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
227
src/cad/fx/viewer/Xform.java
Normal file
227
src/cad/fx/viewer/Xform.java
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011, 2013 Oracle and/or its affiliates.
|
||||||
|
* All rights reserved. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* This file is available and licensed under the following license:
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the distribution.
|
||||||
|
* - Neither the name of Oracle nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cad.fx.viewer;
|
||||||
|
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.scene.transform.Scale;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
|
||||||
|
public class Xform extends Group {
|
||||||
|
|
||||||
|
public enum RotateOrder {
|
||||||
|
XYZ, XZY, YXZ, YZX, ZXY, ZYX
|
||||||
|
}
|
||||||
|
|
||||||
|
public Translate t = new Translate();
|
||||||
|
public Translate p = new Translate();
|
||||||
|
public Translate ip = new Translate();
|
||||||
|
public Rotate rx = new Rotate();
|
||||||
|
|
||||||
|
{
|
||||||
|
rx.setAxis(Rotate.X_AXIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rotate ry = new Rotate();
|
||||||
|
|
||||||
|
{
|
||||||
|
ry.setAxis(Rotate.Y_AXIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rotate rz = new Rotate();
|
||||||
|
|
||||||
|
{
|
||||||
|
rz.setAxis(Rotate.Z_AXIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scale s = new Scale();
|
||||||
|
|
||||||
|
public Xform() {
|
||||||
|
super();
|
||||||
|
getTransforms().addAll(t, rz, ry, rx, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Xform(RotateOrder rotateOrder) {
|
||||||
|
super();
|
||||||
|
// choose the order of rotations based on the rotateOrder
|
||||||
|
switch (rotateOrder) {
|
||||||
|
case XYZ:
|
||||||
|
getTransforms().addAll(t, p, rz, ry, rx, s, ip);
|
||||||
|
break;
|
||||||
|
case XZY:
|
||||||
|
getTransforms().addAll(t, p, ry, rz, rx, s, ip);
|
||||||
|
break;
|
||||||
|
case YXZ:
|
||||||
|
getTransforms().addAll(t, p, rz, rx, ry, s, ip);
|
||||||
|
break;
|
||||||
|
case YZX:
|
||||||
|
getTransforms().addAll(t, p, rx, rz, ry, s, ip); // For Camera
|
||||||
|
break;
|
||||||
|
case ZXY:
|
||||||
|
getTransforms().addAll(t, p, ry, rx, rz, s, ip);
|
||||||
|
break;
|
||||||
|
case ZYX:
|
||||||
|
getTransforms().addAll(t, p, rx, ry, rz, s, ip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslate(double x, double y, double z) {
|
||||||
|
t.setX(x);
|
||||||
|
t.setY(y);
|
||||||
|
t.setZ(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslate(double x, double y) {
|
||||||
|
t.setX(x);
|
||||||
|
t.setY(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot override these methods as they are final:
|
||||||
|
// public void setTranslateX(double x) { t.setX(x); }
|
||||||
|
// public void setTranslateY(double y) { t.setY(y); }
|
||||||
|
// public void setTranslateZ(double z) { t.setZ(z); }
|
||||||
|
// Use these methods instead:
|
||||||
|
public void setTx(double x) {
|
||||||
|
t.setX(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTy(double y) {
|
||||||
|
t.setY(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTz(double z) {
|
||||||
|
t.setZ(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotate(double x, double y, double z) {
|
||||||
|
rx.setAngle(x);
|
||||||
|
ry.setAngle(y);
|
||||||
|
rz.setAngle(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotateX(double x) {
|
||||||
|
rx.setAngle(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotateY(double y) {
|
||||||
|
ry.setAngle(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotateZ(double z) {
|
||||||
|
rz.setAngle(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRx(double x) {
|
||||||
|
rx.setAngle(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRy(double y) {
|
||||||
|
ry.setAngle(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRz(double z) {
|
||||||
|
rz.setAngle(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScale(double scaleFactor) {
|
||||||
|
s.setX(scaleFactor);
|
||||||
|
s.setY(scaleFactor);
|
||||||
|
s.setZ(scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScale(double x, double y, double z) {
|
||||||
|
s.setX(x);
|
||||||
|
s.setY(y);
|
||||||
|
s.setZ(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot override these methods as they are final:
|
||||||
|
// public void setScaleX(double x) { s.setX(x); }
|
||||||
|
// public void setScaleY(double y) { s.setY(y); }
|
||||||
|
// public void setScaleZ(double z) { s.setZ(z); }
|
||||||
|
// Use these methods instead:
|
||||||
|
public void setSx(double x) {
|
||||||
|
s.setX(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSy(double y) {
|
||||||
|
s.setY(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSz(double z) {
|
||||||
|
s.setZ(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPivot(double x, double y, double z) {
|
||||||
|
p.setX(x);
|
||||||
|
p.setY(y);
|
||||||
|
p.setZ(z);
|
||||||
|
ip.setX(-x);
|
||||||
|
ip.setY(-y);
|
||||||
|
ip.setZ(-z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
t.setX(0.0);
|
||||||
|
t.setY(0.0);
|
||||||
|
t.setZ(0.0);
|
||||||
|
rx.setAngle(0.0);
|
||||||
|
ry.setAngle(0.0);
|
||||||
|
rz.setAngle(0.0);
|
||||||
|
s.setX(1.0);
|
||||||
|
s.setY(1.0);
|
||||||
|
s.setZ(1.0);
|
||||||
|
p.setX(0.0);
|
||||||
|
p.setY(0.0);
|
||||||
|
p.setZ(0.0);
|
||||||
|
ip.setX(0.0);
|
||||||
|
ip.setY(0.0);
|
||||||
|
ip.setZ(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetTSP() {
|
||||||
|
t.setX(0.0);
|
||||||
|
t.setY(0.0);
|
||||||
|
t.setZ(0.0);
|
||||||
|
s.setX(1.0);
|
||||||
|
s.setY(1.0);
|
||||||
|
s.setZ(1.0);
|
||||||
|
p.setX(0.0);
|
||||||
|
p.setY(0.0);
|
||||||
|
p.setZ(0.0);
|
||||||
|
ip.setX(0.0);
|
||||||
|
ip.setY(0.0);
|
||||||
|
ip.setZ(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
258
src/cad/math/HMath.java
Normal file
258
src/cad/math/HMath.java
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
package cad.math;
|
||||||
|
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.transform.Affine;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.lang.Math.*;
|
||||||
|
|
||||||
|
public class HMath {
|
||||||
|
|
||||||
|
public static final int X = 0;
|
||||||
|
public static final int Y = 1;
|
||||||
|
public static final int Z = 2;
|
||||||
|
public static final double[] EMPTY = new double[0];
|
||||||
|
public static final Vector X_AXIS = new Vector(1, 0, 0);
|
||||||
|
public static final Vector Y_AXIS = new Vector(0, 1, 0);
|
||||||
|
public static final Vector Z_AXIS = new Vector(0, 0, 1);
|
||||||
|
public static final Vector ZERO = new Vector(0, 0, 0);
|
||||||
|
|
||||||
|
public static final double TOLERANCE = 0.000001;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x*p1 + x*p2 + p3 = 0
|
||||||
|
* x*m1 + x*m2 + m3 = 0
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static double[] solveLinearSystem(double p1, double p2, double p3,
|
||||||
|
double m1, double m2, double m3) {
|
||||||
|
|
||||||
|
double y = (m1 * m3 * p1 + m1 * p3) / (m1 * p2 - m1 * m2 * p1);
|
||||||
|
double x = (-y * p2 - p3) / p1;
|
||||||
|
return new double[]{x, y};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ax^2 + bx + c = 0
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static final double[] solveQuadraticEquation(double a, double b, double c) {
|
||||||
|
final double D = b*b - 4 * a * c;
|
||||||
|
double[] solutions;
|
||||||
|
if (D > 0) {
|
||||||
|
solutions = new double[2];
|
||||||
|
solutions[0] = (-b + sqrt(D)) / (2 * a);
|
||||||
|
solutions[1] = (-b - sqrt(D)) / (2 * a);
|
||||||
|
|
||||||
|
} else if (D == 0) {
|
||||||
|
solutions = new double[2];
|
||||||
|
solutions[0] = -b / (2 * a);
|
||||||
|
} else {
|
||||||
|
solutions = EMPTY;
|
||||||
|
}
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double length(double[] vector) {
|
||||||
|
double sum = 0;
|
||||||
|
for (double v : vector) {
|
||||||
|
sum += v * v;
|
||||||
|
}
|
||||||
|
return Math.sqrt(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] ortoXY(double[] vector) {
|
||||||
|
return new double[]{-vector[Y], vector[X]};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] plus(double[] vector1, double[] vector2) {
|
||||||
|
double[] result = new double[max(vector1.length, vector2.length)];
|
||||||
|
for (int i = 0; i < min(vector1.length, vector2.length); i++) {
|
||||||
|
result[i] = vector1[i] + vector2[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] minus(double[] fromVector, double[] vector) {
|
||||||
|
double[] result = new double[max(fromVector.length, vector.length)];
|
||||||
|
for (int i = 0; i < min(fromVector.length, vector.length); i++) {
|
||||||
|
result[i] = fromVector[i] - vector[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] scale(double[] vector, double factor) {
|
||||||
|
double[] scaled = new double[vector.length];
|
||||||
|
for (int i = 0; i < vector.length; i++) {
|
||||||
|
scaled[i] = vector[i] * factor;
|
||||||
|
}
|
||||||
|
return scaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] scale(double[] vector1, double[] vector2) {
|
||||||
|
double[] result = new double[max(vector1.length, vector2.length)];
|
||||||
|
for (int i = 0; i < min(vector1.length, vector2.length); i++) {
|
||||||
|
result[i] = vector1[i] * vector2[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] norma(double[] vector) {
|
||||||
|
double length = length(vector);
|
||||||
|
double[] norma = new double[vector.length];
|
||||||
|
for (int i = 0; i < vector.length; i++) {
|
||||||
|
norma[i] = vector[i] / length;
|
||||||
|
}
|
||||||
|
return norma;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] getOutOfCS2D(double[] point, double[] abscissa) {
|
||||||
|
double[] ex = norma(abscissa);
|
||||||
|
double[] ey = ortoXY(ex);
|
||||||
|
|
||||||
|
double[] xpart = scale(ex, point[X]);
|
||||||
|
double[] ypart = scale(ey, point[Y]);
|
||||||
|
|
||||||
|
return plus(xpart, ypart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<double[]> circleIntsc(double[] center1, double[] center2, double r1, double r2) {
|
||||||
|
double[] abscissa = minus(center2, center1);
|
||||||
|
double l = length(abscissa);
|
||||||
|
double x = (l * l - r2 * r2 + r1 * r1) / (2 * l);
|
||||||
|
double D = r1 * r1 - x * x;
|
||||||
|
if (D > 0) {
|
||||||
|
List<double[]> solutions = new ArrayList<>(2);
|
||||||
|
solutions.add(plus(center1, getOutOfCS2D(vector(x, + Math.sqrt(D)), abscissa)));
|
||||||
|
solutions.add(plus(center1, getOutOfCS2D(vector(x, - Math.sqrt(D)), abscissa)));
|
||||||
|
return solutions;
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static Vector transform(Vector vector, Matrix transform) {
|
||||||
|
return cross(transform, vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector cross(Matrix transform, Vector vector) {
|
||||||
|
double x = vector.x;
|
||||||
|
double y = vector.y;
|
||||||
|
double z = vector.z;
|
||||||
|
return new Vector(
|
||||||
|
transform.mxx * x + transform.mxy * y + transform.mxz * z + transform.tx,
|
||||||
|
transform.myx * x + transform.myy * y + transform.myz * z + transform.ty,
|
||||||
|
transform.mzx * x + transform.mzy * y + transform.mzz * z + transform.tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Matrix translateMatrix(Vector translation) {
|
||||||
|
Matrix matrix = new Matrix();
|
||||||
|
matrix.tx = translation.x;
|
||||||
|
matrix.ty = translation.y;
|
||||||
|
matrix.tz = translation.z;
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matrix rotateMatrix(double angle, Vector axis, Vector pivot) {
|
||||||
|
final double sin = Math.sin(angle);
|
||||||
|
final double cos = Math.cos(angle);
|
||||||
|
double axisX, axisY, axisZ;
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
|
||||||
|
if (axis == X_AXIS || axis == Y_AXIS || axis == Z_AXIS) {
|
||||||
|
axisX = axis.x;
|
||||||
|
axisY = axis.y;
|
||||||
|
axisZ = axis.z;
|
||||||
|
} else {
|
||||||
|
// normalize
|
||||||
|
final double mag = axis.length();
|
||||||
|
|
||||||
|
if (mag == 0.0) {
|
||||||
|
return m;
|
||||||
|
} else {
|
||||||
|
axisX = axis.x / mag;
|
||||||
|
axisY = axis.y / mag;
|
||||||
|
axisZ = axis.z / mag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double px = pivot.x;
|
||||||
|
double py = pivot.y;
|
||||||
|
double pz = pivot.z;
|
||||||
|
|
||||||
|
m.mxx = cos + axisX * axisX * (1 - cos);
|
||||||
|
m.mxy = axisX * axisY * (1 - cos) - axisZ * sin;
|
||||||
|
m.mxz = axisX * axisZ * (1 - cos) + axisY * sin;
|
||||||
|
|
||||||
|
m.tx = px * (1 - m.mxx) - py * m.mxy - pz * m.mxz;
|
||||||
|
|
||||||
|
m.myx = axisY * axisX * (1 - cos) + axisZ * sin;
|
||||||
|
m.myy = cos + axisY * axisY * (1 - cos);
|
||||||
|
m.myz = axisY * axisZ * (1 - cos) - axisX * sin;
|
||||||
|
m.ty = py * (1 - m.myy) - px * m.myx - pz * m.myz;
|
||||||
|
|
||||||
|
m.mzx = axisZ * axisX * (1 - cos) - axisY * sin;
|
||||||
|
m.mzy = axisZ * axisY * (1 - cos) + axisX * sin;
|
||||||
|
m.mzz = cos + axisZ * axisZ * (1 - cos);
|
||||||
|
m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matrix scaleMatrix(Vector scale, Vector pivot) {
|
||||||
|
double sx = scale.x;
|
||||||
|
double sy = scale.y;
|
||||||
|
double sz = scale.z;
|
||||||
|
return new Matrix(
|
||||||
|
sx, 0, 0, (1 - sx) * pivot.x,
|
||||||
|
0, sy, 0, (1 - sy) * pivot.y,
|
||||||
|
0, 0, sz, (1 - sz) * pivot.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matrix combine(Matrix... matrices) {
|
||||||
|
if (matrices.length == 0) {
|
||||||
|
return new Matrix();
|
||||||
|
}
|
||||||
|
if (matrices.length == 1) {
|
||||||
|
return matrices[0];
|
||||||
|
}
|
||||||
|
Matrix m = matrices[0];
|
||||||
|
|
||||||
|
for (int i = 1; i < matrices.length; i++) {
|
||||||
|
m = m.combine(matrices[i]);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] vector(double... data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector[] translate(Vector[] vectors, Vector delta) {
|
||||||
|
vectors = copy(vectors);
|
||||||
|
for (int i = 0; i < vectors.length; i++) {
|
||||||
|
vectors[i].x += delta.x;
|
||||||
|
vectors[i].y += delta.y;
|
||||||
|
vectors[i].z += delta.z;
|
||||||
|
}
|
||||||
|
return vectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector[] copy(Vector[] vectors) {
|
||||||
|
Vector[] copy = new Vector[vectors.length];
|
||||||
|
for (int i = 0; i < vectors.length; i++) {
|
||||||
|
copy[i] = vectors[i].copy();
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean areEquals(double v1, double v2, double tolerance) {
|
||||||
|
return abs(v1 - v2) < tolerance;
|
||||||
|
}
|
||||||
|
}
|
||||||
137
src/cad/math/Matrix.java
Normal file
137
src/cad/math/Matrix.java
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
package cad.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by verastov on 7/8/14.
|
||||||
|
*/
|
||||||
|
public class Matrix {
|
||||||
|
|
||||||
|
public double
|
||||||
|
mxx, mxy, mxz, tx,
|
||||||
|
myx, myy, myz, ty,
|
||||||
|
mzx, mzy, mzz, tz;
|
||||||
|
|
||||||
|
public Matrix() {
|
||||||
|
mxx = 1; mxy = 0; mxz = 0; tx = 0;
|
||||||
|
myx = 0; myy = 1; myz = 0; ty = 0;
|
||||||
|
mzx = 0; mzy = 0; mzz = 1; tz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix(Vector[] basis) {
|
||||||
|
Vector[] b = basis;
|
||||||
|
mxx = b[0].x; mxy = b[1].x; mxz = b[2].x; tx = 0;
|
||||||
|
myx = b[0].y; myy = b[1].y; myz = b[2].y; ty = 0;
|
||||||
|
mzx = b[0].z; mzy = b[1].z; mzz = b[2].z; tz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix(
|
||||||
|
double mxx, double mxy, double mxz,
|
||||||
|
double myx, double myy, double myz,
|
||||||
|
double mzx, double mzy, double mzz
|
||||||
|
) {
|
||||||
|
this.mxx = mxx; this.mxy = mxy; this.mxz = mxz;
|
||||||
|
this.myx = myx; this.myy = myy; this.myz = myz;
|
||||||
|
this.mzx = mzx; this.mzy = mzy; this.mzz = mzz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix(
|
||||||
|
double mxx, double mxy, double mxz, double tx,
|
||||||
|
double myx, double myy, double myz, double ty,
|
||||||
|
double mzx, double mzy, double mzz, double tz
|
||||||
|
) {
|
||||||
|
this.mxx = mxx; this.mxy = mxy; this.mxz = mxz; this.tx = tx;
|
||||||
|
this.myx = myx; this.myy = myy; this.myz = myz; this.ty = ty;
|
||||||
|
this.mzx = mzx; this.mzy = mzy; this.mzz = mzz; this.tz = tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(Matrix m) {
|
||||||
|
this.mxx = m.mxx; this.mxy = m.mxy; this.mxz = m.mxz; this.tx = m.tx;
|
||||||
|
this.myx = m.myx; this.myy = m.myy; this.myz = m.myz; this.ty = m.ty;
|
||||||
|
this.mzx = m.mzx; this.mzy = m.mzy; this.mzz = m.mzz; this.tz = m.tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix invert() {
|
||||||
|
|
||||||
|
final double det =
|
||||||
|
mxx * (myy * mzz - mzy * myz) +
|
||||||
|
mxy * (myz * mzx - mzz * myx) +
|
||||||
|
mxz * (myx * mzy - mzx * myy);
|
||||||
|
|
||||||
|
if (det == 0.0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final double cxx = myy * mzz - myz * mzy;
|
||||||
|
final double cyx = - myx * mzz + myz * mzx;
|
||||||
|
final double czx = myx * mzy - myy * mzx;
|
||||||
|
final double cxt = - mxy * (myz * tz - mzz * ty)
|
||||||
|
- mxz * (ty * mzy - tz * myy)
|
||||||
|
- tx * (myy * mzz - mzy * myz);
|
||||||
|
final double cxy = - mxy * mzz + mxz * mzy;
|
||||||
|
final double cyy = mxx * mzz - mxz * mzx;
|
||||||
|
final double czy = - mxx * mzy + mxy * mzx;
|
||||||
|
final double cyt = mxx * (myz * tz - mzz * ty)
|
||||||
|
+ mxz * (ty * mzx - tz * myx)
|
||||||
|
+ tx * (myx * mzz - mzx * myz);
|
||||||
|
final double cxz = mxy * myz - mxz * myy;
|
||||||
|
final double cyz = - mxx * myz + mxz * myx;
|
||||||
|
final double czz = mxx * myy - mxy * myx;
|
||||||
|
final double czt = - mxx * (myy * tz - mzy * ty)
|
||||||
|
- mxy * (ty * mzx - tz * myx)
|
||||||
|
- tx * (myx * mzy - mzx * myy);
|
||||||
|
|
||||||
|
Matrix result = new Matrix();
|
||||||
|
result.mxx = cxx / det;
|
||||||
|
result.mxy = cxy / det;
|
||||||
|
result.mxz = cxz / det;
|
||||||
|
result.tx = cxt / det;
|
||||||
|
result.myx = cyx / det;
|
||||||
|
result.myy = cyy / det;
|
||||||
|
result.myz = cyz / det;
|
||||||
|
result.ty = cyt / det;
|
||||||
|
result.mzx = czx / det;
|
||||||
|
result.mzy = czy / det;
|
||||||
|
result.mzz = czz / det;
|
||||||
|
result.tz = czt / det;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix combine(Matrix transform) {
|
||||||
|
final double txx = transform.mxx;
|
||||||
|
final double txy = transform.mxy;
|
||||||
|
final double txz = transform.mxz;
|
||||||
|
final double ttx = transform.tx;
|
||||||
|
final double tyx = transform.myx;
|
||||||
|
final double tyy = transform.myy;
|
||||||
|
final double tyz = transform.myz;
|
||||||
|
final double tty = transform.ty;
|
||||||
|
final double tzx = transform.mzx;
|
||||||
|
final double tzy = transform.mzy;
|
||||||
|
final double tzz = transform.mzz;
|
||||||
|
final double ttz = transform.tz;
|
||||||
|
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
m.mxx = (this.mxx * txx + this.mxy * tyx + this.mxz * tzx);
|
||||||
|
m.mxy = (this.mxx * txy + this.mxy * tyy + this.mxz * tzy);
|
||||||
|
m.mxz = (this.mxx * txz + this.mxy * tyz + this.mxz * tzz);
|
||||||
|
m.tx = (this.mxx * ttx + this.mxy * tty + this.mxz * ttz + this.tx);
|
||||||
|
m.myx = (this.myx * txx + this.myy * tyx + this.myz * tzx);
|
||||||
|
m.myy = (this.myx * txy + this.myy * tyy + this.myz * tzy);
|
||||||
|
m.myz = (this.myx * txz + this.myy * tyz + this.myz * tzz);
|
||||||
|
m.ty = (this.myx * ttx + this.myy * tty + this.myz * ttz + this.ty);
|
||||||
|
m.mzx = (this.mzx * txx + this.mzy * tyx + this.mzz * tzx);
|
||||||
|
m.mzy = (this.mzx * txy + this.mzy * tyy + this.mzz * tzy);
|
||||||
|
m.mzz = (this.mzx * txz + this.mzy * tyz + this.mzz * tzz);
|
||||||
|
m.tz = (this.mzx * ttx + this.mzy * tty + this.mzz * ttz + this.tz);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String str = "";
|
||||||
|
str += String.format("%.4f, %.4f, %.4f, %.4f\n", mxx, mxy, mxz, tx);
|
||||||
|
str += String.format("%.4f, %.4f, %.4f, %.4f\n", myx, myy, myz, ty);
|
||||||
|
str += String.format("%.4f, %.4f, %.4f, %.4f" , mzx, mzy, mzz, tz);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/cad/math/Vector.java
Normal file
105
src/cad/math/Vector.java
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
package cad.math;
|
||||||
|
|
||||||
|
public class Vector {
|
||||||
|
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
|
||||||
|
public Vector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector(double x, double y, double z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector(Vector vector) {
|
||||||
|
this(vector.x, vector.y, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector(double x, double y) {
|
||||||
|
this(x, y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector(double[] data) {
|
||||||
|
if (data.length > 0) {
|
||||||
|
x = data[0];
|
||||||
|
if (data.length > 1) {
|
||||||
|
y = data[1];
|
||||||
|
if (data.length > 2) {
|
||||||
|
z = data[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector scale(double factor) {
|
||||||
|
return scale(factor, factor, factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector scale(double dx, double dy, double dz) {
|
||||||
|
return new Vector(x * dx, y * dy, z * dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double dot(Vector vector) {
|
||||||
|
return x * vector.x + y * vector.y + z * vector.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector copy() {
|
||||||
|
return new Vector(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double length() {
|
||||||
|
return Math.sqrt(x*x + y*y + z*z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("[%.4f, %.4f, %.4f]", x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector minus(Vector vector) {
|
||||||
|
return new Vector(x - vector.x, y - vector.y, z - vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector plus(Vector vector) {
|
||||||
|
return new Vector(x + vector.x, y + vector.y, z + vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector plus(double dx, double dy, double dz) {
|
||||||
|
return new Vector(x + dx, y + dy, z + dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector normalize() {
|
||||||
|
final double mag = length();
|
||||||
|
if (mag == 0.0) {
|
||||||
|
return new Vector(0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
return new Vector(x / mag, y / mag, z / mag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector cross(Vector a) {
|
||||||
|
return new Vector(
|
||||||
|
this.y * a.z - this.z * a.y,
|
||||||
|
this.z * a.x - this.x * a.z,
|
||||||
|
this.x * a.y - this.y * a.x
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean slightlyEqualTo(Vector vector) {
|
||||||
|
return equalTo(vector, HMath.TOLERANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equalTo(Vector vector, double tolerance) {
|
||||||
|
return
|
||||||
|
HMath.areEquals(x, vector.x, tolerance) &&
|
||||||
|
HMath.areEquals(y, vector.y, tolerance) &&
|
||||||
|
HMath.areEquals(z, vector.z, tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector negate() {
|
||||||
|
return scale(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
127
src/org/poly2tri/Poly2Tri.java
Normal file
127
src/org/poly2tri/Poly2Tri.java
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.polygon.Polygon;
|
||||||
|
import org.poly2tri.geometry.polygon.PolygonSet;
|
||||||
|
import org.poly2tri.triangulation.Triangulatable;
|
||||||
|
import org.poly2tri.triangulation.TriangulationAlgorithm;
|
||||||
|
import org.poly2tri.triangulation.TriangulationContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationMode;
|
||||||
|
import org.poly2tri.triangulation.TriangulationProcess;
|
||||||
|
import org.poly2tri.triangulation.delaunay.sweep.DTSweep;
|
||||||
|
import org.poly2tri.triangulation.delaunay.sweep.DTSweepContext;
|
||||||
|
import org.poly2tri.triangulation.sets.ConstrainedPointSet;
|
||||||
|
import org.poly2tri.triangulation.sets.PointSet;
|
||||||
|
import org.poly2tri.triangulation.util.PolygonGenerator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class Poly2Tri
|
||||||
|
{
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger( Poly2Tri.class );
|
||||||
|
|
||||||
|
private static final TriangulationAlgorithm _defaultAlgorithm = TriangulationAlgorithm.DTSweep;
|
||||||
|
|
||||||
|
public static void triangulate( PolygonSet ps )
|
||||||
|
{
|
||||||
|
TriangulationContext<?> tcx = createContext( _defaultAlgorithm );
|
||||||
|
for( Polygon p : ps.getPolygons() )
|
||||||
|
{
|
||||||
|
tcx.prepareTriangulation( p );
|
||||||
|
triangulate( tcx );
|
||||||
|
tcx.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void triangulate( Polygon p )
|
||||||
|
{
|
||||||
|
triangulate( _defaultAlgorithm, p );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void triangulate( ConstrainedPointSet cps )
|
||||||
|
{
|
||||||
|
triangulate( _defaultAlgorithm, cps );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void triangulate( PointSet ps )
|
||||||
|
{
|
||||||
|
triangulate( _defaultAlgorithm, ps );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TriangulationContext<?> createContext( TriangulationAlgorithm algorithm )
|
||||||
|
{
|
||||||
|
switch( algorithm )
|
||||||
|
{
|
||||||
|
case DTSweep:
|
||||||
|
default:
|
||||||
|
return new DTSweepContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void triangulate( TriangulationAlgorithm algorithm,
|
||||||
|
Triangulatable t )
|
||||||
|
{
|
||||||
|
TriangulationContext<?> tcx;
|
||||||
|
|
||||||
|
// long time = System.nanoTime();
|
||||||
|
tcx = createContext( algorithm );
|
||||||
|
tcx.prepareTriangulation( t );
|
||||||
|
triangulate( tcx );
|
||||||
|
// logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void triangulate( TriangulationContext<?> tcx )
|
||||||
|
{
|
||||||
|
switch( tcx.algorithm() )
|
||||||
|
{
|
||||||
|
case DTSweep:
|
||||||
|
default:
|
||||||
|
DTSweep.triangulate( (DTSweepContext)tcx );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will do a warmup run to let the JVM optimize the triangulation code
|
||||||
|
*/
|
||||||
|
public static void warmup()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* After a method is run 10000 times, the Hotspot compiler will compile
|
||||||
|
* it into native code. Periodically, the Hotspot compiler may recompile
|
||||||
|
* the method. After an unspecified amount of time, then the compilation
|
||||||
|
* system should become quiet.
|
||||||
|
*/
|
||||||
|
Polygon poly = PolygonGenerator.RandomCircleSweep2( 50, 50000 );
|
||||||
|
TriangulationProcess process = new TriangulationProcess();
|
||||||
|
process.triangulate( poly );
|
||||||
|
}
|
||||||
|
}
|
||||||
273
src/org/poly2tri/geometry/polygon/Polygon.java
Normal file
273
src/org/poly2tri/geometry/polygon/Polygon.java
Normal file
|
|
@ -0,0 +1,273 @@
|
||||||
|
package org.poly2tri.geometry.polygon;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.Triangulatable;
|
||||||
|
import org.poly2tri.triangulation.TriangulationContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationMode;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class Polygon implements Triangulatable
|
||||||
|
{
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger( Polygon.class );
|
||||||
|
|
||||||
|
protected ArrayList<TriangulationPoint> _points = new ArrayList<TriangulationPoint>();
|
||||||
|
protected ArrayList<TriangulationPoint> _steinerPoints;
|
||||||
|
protected ArrayList<Polygon> _holes;
|
||||||
|
|
||||||
|
protected List<DelaunayTriangle> m_triangles;
|
||||||
|
|
||||||
|
protected PolygonPoint _last;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To create a polygon we need atleast 3 separate points
|
||||||
|
*
|
||||||
|
* @param p1
|
||||||
|
* @param p2
|
||||||
|
* @param p3
|
||||||
|
*/
|
||||||
|
public Polygon( PolygonPoint p1, PolygonPoint p2, PolygonPoint p3 )
|
||||||
|
{
|
||||||
|
p1._next = p2;
|
||||||
|
p2._next = p3;
|
||||||
|
p3._next = p1;
|
||||||
|
p1._previous = p3;
|
||||||
|
p2._previous = p1;
|
||||||
|
p3._previous = p2;
|
||||||
|
_points.add( p1 );
|
||||||
|
_points.add( p2 );
|
||||||
|
_points.add( p3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires atleast 3 points
|
||||||
|
* @param points - ordered list of points forming the polygon.
|
||||||
|
* No duplicates are allowed
|
||||||
|
*/
|
||||||
|
public Polygon( List<PolygonPoint> points )
|
||||||
|
{
|
||||||
|
// Lets do one sanity check that first and last point hasn't got same position
|
||||||
|
// Its something that often happen when importing polygon data from other formats
|
||||||
|
if( points.get(0).equals( points.get(points.size()-1) ) )
|
||||||
|
{
|
||||||
|
logger.warn( "Removed duplicate point");
|
||||||
|
points.remove( points.size()-1 );
|
||||||
|
}
|
||||||
|
_points.addAll( points );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires atleast 3 points
|
||||||
|
*
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
public Polygon( PolygonPoint[] points )
|
||||||
|
{
|
||||||
|
this( Arrays.asList( points ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationMode getTriangulationMode()
|
||||||
|
{
|
||||||
|
return TriangulationMode.POLYGON;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int pointCount()
|
||||||
|
{
|
||||||
|
int count = _points.size();
|
||||||
|
if( _steinerPoints != null )
|
||||||
|
{
|
||||||
|
count += _steinerPoints.size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSteinerPoint( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
if( _steinerPoints == null )
|
||||||
|
{
|
||||||
|
_steinerPoints = new ArrayList<TriangulationPoint>();
|
||||||
|
}
|
||||||
|
_steinerPoints.add( point );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSteinerPoints( List<TriangulationPoint> points )
|
||||||
|
{
|
||||||
|
if( _steinerPoints == null )
|
||||||
|
{
|
||||||
|
_steinerPoints = new ArrayList<TriangulationPoint>();
|
||||||
|
}
|
||||||
|
_steinerPoints.addAll( points );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearSteinerPoints()
|
||||||
|
{
|
||||||
|
if( _steinerPoints != null )
|
||||||
|
{
|
||||||
|
_steinerPoints.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumes: that given polygon is fully inside the current polygon
|
||||||
|
* @param poly - a subtraction polygon
|
||||||
|
*/
|
||||||
|
public void addHole( Polygon poly )
|
||||||
|
{
|
||||||
|
if( _holes == null )
|
||||||
|
{
|
||||||
|
_holes = new ArrayList<Polygon>();
|
||||||
|
}
|
||||||
|
_holes.add( poly );
|
||||||
|
// XXX: tests could be made here to be sure it is fully inside
|
||||||
|
// addSubtraction( poly.getPoints() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will insert a point in the polygon after given point
|
||||||
|
*
|
||||||
|
* @param a
|
||||||
|
* @param b
|
||||||
|
* @param p
|
||||||
|
*/
|
||||||
|
public void insertPointAfter( PolygonPoint a, PolygonPoint newPoint )
|
||||||
|
{
|
||||||
|
// Validate that
|
||||||
|
int index = _points.indexOf( a );
|
||||||
|
if( index != -1 )
|
||||||
|
{
|
||||||
|
newPoint.setNext( a.getNext() );
|
||||||
|
newPoint.setPrevious( a );
|
||||||
|
a.getNext().setPrevious( newPoint );
|
||||||
|
a.setNext( newPoint );
|
||||||
|
_points.add( index+1, newPoint );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "Tried to insert a point into a Polygon after a point not belonging to the Polygon" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPoints( List<PolygonPoint> list )
|
||||||
|
{
|
||||||
|
PolygonPoint first;
|
||||||
|
for( PolygonPoint p : list )
|
||||||
|
{
|
||||||
|
p.setPrevious( _last );
|
||||||
|
if( _last != null )
|
||||||
|
{
|
||||||
|
p.setNext( _last.getNext() );
|
||||||
|
_last.setNext( p );
|
||||||
|
}
|
||||||
|
_last = p;
|
||||||
|
_points.add( p );
|
||||||
|
}
|
||||||
|
first = (PolygonPoint)_points.get(0);
|
||||||
|
_last.setNext( first );
|
||||||
|
first.setPrevious( _last );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will add a point after the last point added
|
||||||
|
*
|
||||||
|
* @param p
|
||||||
|
*/
|
||||||
|
public void addPoint(PolygonPoint p )
|
||||||
|
{
|
||||||
|
p.setPrevious( _last );
|
||||||
|
p.setNext( _last.getNext() );
|
||||||
|
_last.setNext( p );
|
||||||
|
_points.add( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePoint( PolygonPoint p )
|
||||||
|
{
|
||||||
|
PolygonPoint next, prev;
|
||||||
|
|
||||||
|
next = p.getNext();
|
||||||
|
prev = p.getPrevious();
|
||||||
|
prev.setNext( next );
|
||||||
|
next.setPrevious( prev );
|
||||||
|
_points.remove( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolygonPoint getPoint()
|
||||||
|
{
|
||||||
|
return _last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TriangulationPoint> getPoints()
|
||||||
|
{
|
||||||
|
return _points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DelaunayTriangle> getTriangles()
|
||||||
|
{
|
||||||
|
return m_triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTriangle( DelaunayTriangle t )
|
||||||
|
{
|
||||||
|
m_triangles.add( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTriangles( List<DelaunayTriangle> list )
|
||||||
|
{
|
||||||
|
m_triangles.addAll( list );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearTriangulation()
|
||||||
|
{
|
||||||
|
if( m_triangles != null )
|
||||||
|
{
|
||||||
|
m_triangles.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates constraints and populates the context with points
|
||||||
|
*/
|
||||||
|
public void prepareTriangulation( TriangulationContext<?> tcx )
|
||||||
|
{
|
||||||
|
if( m_triangles == null )
|
||||||
|
{
|
||||||
|
m_triangles = new ArrayList<DelaunayTriangle>( _points.size() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_triangles.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outer constraints
|
||||||
|
for( int i = 0; i < _points.size()-1 ; i++ )
|
||||||
|
{
|
||||||
|
tcx.newConstraint( _points.get( i ), _points.get( i+1 ) );
|
||||||
|
}
|
||||||
|
tcx.newConstraint( _points.get( 0 ), _points.get( _points.size()-1 ) );
|
||||||
|
tcx.addPoints( _points );
|
||||||
|
|
||||||
|
// Hole constraints
|
||||||
|
if( _holes != null )
|
||||||
|
{
|
||||||
|
for( Polygon p : _holes )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < p._points.size()-1 ; i++ )
|
||||||
|
{
|
||||||
|
tcx.newConstraint( p._points.get( i ), p._points.get( i+1 ) );
|
||||||
|
}
|
||||||
|
tcx.newConstraint( p._points.get( 0 ), p._points.get( p._points.size()-1 ) );
|
||||||
|
tcx.addPoints( p._points );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _steinerPoints != null )
|
||||||
|
{
|
||||||
|
tcx.addPoints( _steinerPoints );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
src/org/poly2tri/geometry/polygon/PolygonPoint.java
Normal file
39
src/org/poly2tri/geometry/polygon/PolygonPoint.java
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.poly2tri.geometry.polygon;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.point.TPoint;
|
||||||
|
|
||||||
|
public class PolygonPoint extends TPoint
|
||||||
|
{
|
||||||
|
protected PolygonPoint _next;
|
||||||
|
protected PolygonPoint _previous;
|
||||||
|
|
||||||
|
public PolygonPoint( double x, double y )
|
||||||
|
{
|
||||||
|
super( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolygonPoint( double x, double y, double z )
|
||||||
|
{
|
||||||
|
super( x, y, z );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrevious( PolygonPoint p )
|
||||||
|
{
|
||||||
|
_previous = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNext( PolygonPoint p )
|
||||||
|
{
|
||||||
|
_next = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolygonPoint getNext()
|
||||||
|
{
|
||||||
|
return _next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolygonPoint getPrevious()
|
||||||
|
{
|
||||||
|
return _previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/org/poly2tri/geometry/polygon/PolygonSet.java
Normal file
58
src/org/poly2tri/geometry/polygon/PolygonSet.java
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.geometry.polygon;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PolygonSet
|
||||||
|
{
|
||||||
|
protected ArrayList<Polygon> _polygons = new ArrayList<Polygon>();
|
||||||
|
|
||||||
|
public PolygonSet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolygonSet( Polygon poly )
|
||||||
|
{
|
||||||
|
_polygons.add( poly );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add( Polygon p )
|
||||||
|
{
|
||||||
|
_polygons.add( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Polygon> getPolygons()
|
||||||
|
{
|
||||||
|
return _polygons;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/org/poly2tri/geometry/polygon/PolygonUtil.java
Normal file
15
src/org/poly2tri/geometry/polygon/PolygonUtil.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.poly2tri.geometry.polygon;
|
||||||
|
|
||||||
|
public class PolygonUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
* @param polygon
|
||||||
|
*/
|
||||||
|
public static void validate( Polygon polygon )
|
||||||
|
{
|
||||||
|
// TODO: implement
|
||||||
|
// 1. Check for duplicate points
|
||||||
|
// 2. Check for intersecting sides
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/org/poly2tri/geometry/primitives/Edge.java
Normal file
17
src/org/poly2tri/geometry/primitives/Edge.java
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
package org.poly2tri.geometry.primitives;
|
||||||
|
|
||||||
|
public abstract class Edge<A extends Point>
|
||||||
|
{
|
||||||
|
protected A p;
|
||||||
|
protected A q;
|
||||||
|
|
||||||
|
public A getP()
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A getQ()
|
||||||
|
{
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/org/poly2tri/geometry/primitives/Point.java
Normal file
31
src/org/poly2tri/geometry/primitives/Point.java
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.poly2tri.geometry.primitives;
|
||||||
|
|
||||||
|
public abstract class Point
|
||||||
|
{
|
||||||
|
public abstract double getX();
|
||||||
|
public abstract double getY();
|
||||||
|
public abstract double getZ();
|
||||||
|
|
||||||
|
public abstract float getXf();
|
||||||
|
public abstract float getYf();
|
||||||
|
public abstract float getZf();
|
||||||
|
|
||||||
|
public abstract void set( double x, double y, double z );
|
||||||
|
|
||||||
|
protected static int calculateHashCode( double x, double y, double z)
|
||||||
|
{
|
||||||
|
int result = 17;
|
||||||
|
|
||||||
|
final long a = Double.doubleToLongBits(x);
|
||||||
|
result += 31 * result + (int) (a ^ (a >>> 32));
|
||||||
|
|
||||||
|
final long b = Double.doubleToLongBits(y);
|
||||||
|
result += 31 * result + (int) (b ^ (b >>> 32));
|
||||||
|
|
||||||
|
final long c = Double.doubleToLongBits(z);
|
||||||
|
result += 31 * result + (int) (c ^ (c >>> 32));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/org/poly2tri/transform/coordinate/AnyToXYTransform.java
Normal file
71
src/org/poly2tri/transform/coordinate/AnyToXYTransform.java
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package org.poly2tri.transform.coordinate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transform that aligns given source normal with the XY plane normal [0,0,1]
|
||||||
|
*
|
||||||
|
* @author thahlen@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AnyToXYTransform extends Matrix3Transform
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Assumes source normal is normalized
|
||||||
|
*/
|
||||||
|
public AnyToXYTransform( double nx, double ny, double nz )
|
||||||
|
{
|
||||||
|
setSourceNormal( nx, ny, nz );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumes source normal is normalized
|
||||||
|
*
|
||||||
|
* @param nx
|
||||||
|
* @param ny
|
||||||
|
* @param nz
|
||||||
|
*/
|
||||||
|
public void setSourceNormal( double nx, double ny, double nz )
|
||||||
|
{
|
||||||
|
double h,f,c,vx,vy,hvx;
|
||||||
|
|
||||||
|
vx = -ny;
|
||||||
|
vy = nx;
|
||||||
|
c = nz;
|
||||||
|
|
||||||
|
h = (1-c)/(1-c*c);
|
||||||
|
hvx = h*vx;
|
||||||
|
f = (c < 0) ? -c : c;
|
||||||
|
|
||||||
|
if( f < 1.0 - 1.0E-4 )
|
||||||
|
{
|
||||||
|
m00=c + hvx*vx;
|
||||||
|
m01=hvx*vy;
|
||||||
|
m02=-vy;
|
||||||
|
m10=hvx*vy;
|
||||||
|
m11=c + h*vy*vy;
|
||||||
|
m12=vx;
|
||||||
|
m20=vy;
|
||||||
|
m21=-vx;
|
||||||
|
m22=c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if "from" and "to" vectors are nearly parallel
|
||||||
|
m00=1;
|
||||||
|
m01=0;
|
||||||
|
m02=0;
|
||||||
|
m10=0;
|
||||||
|
m11=1;
|
||||||
|
m12=0;
|
||||||
|
m20=0;
|
||||||
|
m21=0;
|
||||||
|
if( c > 0 )
|
||||||
|
{
|
||||||
|
m22=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m22=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.poly2tri.transform.coordinate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.primitives.Point;
|
||||||
|
|
||||||
|
public abstract interface CoordinateTransform
|
||||||
|
{
|
||||||
|
public abstract void transform(Point p, Point store);
|
||||||
|
public abstract void transform(Point p);
|
||||||
|
public abstract void transform(List<? extends Point> list);
|
||||||
|
}
|
||||||
38
src/org/poly2tri/transform/coordinate/Matrix3Transform.java
Normal file
38
src/org/poly2tri/transform/coordinate/Matrix3Transform.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package org.poly2tri.transform.coordinate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.primitives.Point;
|
||||||
|
|
||||||
|
public abstract class Matrix3Transform implements CoordinateTransform
|
||||||
|
{
|
||||||
|
protected double m00,m01,m02,m10,m11,m12,m20,m21,m22;
|
||||||
|
|
||||||
|
public void transform( Point p, Point store )
|
||||||
|
{
|
||||||
|
final double px = p.getX();
|
||||||
|
final double py = p.getY();
|
||||||
|
final double pz = p.getZ();
|
||||||
|
store.set(m00 * px + m01 * py + m02 * pz,
|
||||||
|
m10 * px + m11 * py + m12 * pz,
|
||||||
|
m20 * px + m21 * py + m22 * pz );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transform( Point p )
|
||||||
|
{
|
||||||
|
final double px = p.getX();
|
||||||
|
final double py = p.getY();
|
||||||
|
final double pz = p.getZ();
|
||||||
|
p.set(m00 * px + m01 * py + m02 * pz,
|
||||||
|
m10 * px + m11 * py + m12 * pz,
|
||||||
|
m20 * px + m21 * py + m22 * pz );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transform( List<? extends Point> list )
|
||||||
|
{
|
||||||
|
for( Point p : list )
|
||||||
|
{
|
||||||
|
transform( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/org/poly2tri/transform/coordinate/NoTransform.java
Normal file
21
src/org/poly2tri/transform/coordinate/NoTransform.java
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.poly2tri.transform.coordinate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.primitives.Point;
|
||||||
|
|
||||||
|
public class NoTransform implements CoordinateTransform
|
||||||
|
{
|
||||||
|
public void transform( Point p, Point store )
|
||||||
|
{
|
||||||
|
store.set( p.getX(), p.getY(), p.getZ() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transform( Point p )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transform( List<? extends Point> list )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/org/poly2tri/transform/coordinate/XYToAnyTransform.java
Normal file
74
src/org/poly2tri/transform/coordinate/XYToAnyTransform.java
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package org.poly2tri.transform.coordinate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transform that aligns the XY plane normal [0,0,1] with any given target normal
|
||||||
|
*
|
||||||
|
* http://www.cs.brown.edu/~jfh/papers/Moller-EBA-1999/paper.pdf
|
||||||
|
*
|
||||||
|
* @author thahlen@gmail.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class XYToAnyTransform extends Matrix3Transform
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Assumes target normal is normalized
|
||||||
|
*/
|
||||||
|
public XYToAnyTransform( double nx, double ny, double nz )
|
||||||
|
{
|
||||||
|
setTargetNormal( nx, ny, nz );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumes target normal is normalized
|
||||||
|
*
|
||||||
|
* @param nx
|
||||||
|
* @param ny
|
||||||
|
* @param nz
|
||||||
|
*/
|
||||||
|
public void setTargetNormal( double nx, double ny, double nz )
|
||||||
|
{
|
||||||
|
double h,f,c,vx,vy,hvx;
|
||||||
|
|
||||||
|
vx = ny;
|
||||||
|
vy = -nx;
|
||||||
|
c = nz;
|
||||||
|
|
||||||
|
h = (1-c)/(1-c*c);
|
||||||
|
hvx = h*vx;
|
||||||
|
f = (c < 0) ? -c : c;
|
||||||
|
|
||||||
|
if( f < 1.0 - 1.0E-4 )
|
||||||
|
{
|
||||||
|
m00=c + hvx*vx;
|
||||||
|
m01=hvx*vy;
|
||||||
|
m02=-vy;
|
||||||
|
m10=hvx*vy;
|
||||||
|
m11=c + h*vy*vy;
|
||||||
|
m12=vx;
|
||||||
|
m20=vy;
|
||||||
|
m21=-vx;
|
||||||
|
m22=c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if "from" and "to" vectors are nearly parallel
|
||||||
|
m00=1;
|
||||||
|
m01=0;
|
||||||
|
m02=0;
|
||||||
|
m10=0;
|
||||||
|
m11=1;
|
||||||
|
m12=0;
|
||||||
|
m20=0;
|
||||||
|
m21=0;
|
||||||
|
if( c > 0 )
|
||||||
|
{
|
||||||
|
m22=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m22=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/org/poly2tri/triangulation/Triangulatable.java
Normal file
22
src/org/poly2tri/triangulation/Triangulatable.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
public interface Triangulatable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Preparations needed before triangulation start should be handled here
|
||||||
|
* @param tcx
|
||||||
|
*/
|
||||||
|
public void prepareTriangulation(TriangulationContext<?> tcx);
|
||||||
|
|
||||||
|
public List<DelaunayTriangle> getTriangles();
|
||||||
|
public List<TriangulationPoint> getPoints();
|
||||||
|
public void addTriangle(DelaunayTriangle t);
|
||||||
|
public void addTriangles(List<DelaunayTriangle> list);
|
||||||
|
public void clearTriangulation();
|
||||||
|
|
||||||
|
public TriangulationMode getTriangulationMode();
|
||||||
|
}
|
||||||
36
src/org/poly2tri/triangulation/TriangulationAlgorithm.java
Normal file
36
src/org/poly2tri/triangulation/TriangulationAlgorithm.java
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
public enum TriangulationAlgorithm
|
||||||
|
{
|
||||||
|
DTSweep
|
||||||
|
}
|
||||||
55
src/org/poly2tri/triangulation/TriangulationConstraint.java
Normal file
55
src/org/poly2tri/triangulation/TriangulationConstraint.java
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces a triangle edge between two points p and q
|
||||||
|
* when triangulating. For example used to enforce
|
||||||
|
* Polygon Edges during a polygon triangulation.
|
||||||
|
*
|
||||||
|
* @author Thomas Åhlén, thahlen@gmail.com
|
||||||
|
*/
|
||||||
|
public class TriangulationConstraint
|
||||||
|
{
|
||||||
|
protected TriangulationPoint p;
|
||||||
|
protected TriangulationPoint q;
|
||||||
|
|
||||||
|
public TriangulationPoint getP()
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationPoint getQ()
|
||||||
|
{
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
171
src/org/poly2tri/triangulation/TriangulationContext.java
Normal file
171
src/org/poly2tri/triangulation/TriangulationContext.java
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
public abstract class TriangulationContext<A extends TriangulationDebugContext>
|
||||||
|
{
|
||||||
|
protected A _debug;
|
||||||
|
protected boolean _debugEnabled = false;
|
||||||
|
|
||||||
|
protected ArrayList<DelaunayTriangle> _triList = new ArrayList<DelaunayTriangle>();
|
||||||
|
|
||||||
|
protected ArrayList<TriangulationPoint> _points = new ArrayList<TriangulationPoint>(200);
|
||||||
|
protected TriangulationMode _triangulationMode;
|
||||||
|
protected Triangulatable _triUnit;
|
||||||
|
|
||||||
|
private boolean _terminated = false;
|
||||||
|
private boolean _waitUntilNotified;
|
||||||
|
|
||||||
|
private int _stepTime = -1;
|
||||||
|
private int _stepCount = 0;
|
||||||
|
public int getStepCount() { return _stepCount; }
|
||||||
|
|
||||||
|
public void done()
|
||||||
|
{
|
||||||
|
_stepCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TriangulationAlgorithm algorithm();
|
||||||
|
|
||||||
|
public void prepareTriangulation( Triangulatable t )
|
||||||
|
{
|
||||||
|
_triUnit = t;
|
||||||
|
_triangulationMode = t.getTriangulationMode();
|
||||||
|
t.prepareTriangulation( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TriangulationConstraint newConstraint( TriangulationPoint a, TriangulationPoint b );
|
||||||
|
|
||||||
|
public void addToList( DelaunayTriangle triangle )
|
||||||
|
{
|
||||||
|
_triList.add( triangle );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DelaunayTriangle> getTriangles()
|
||||||
|
{
|
||||||
|
return _triList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Triangulatable getTriangulatable()
|
||||||
|
{
|
||||||
|
return _triUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TriangulationPoint> getPoints()
|
||||||
|
{
|
||||||
|
return _points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void update(String message)
|
||||||
|
{
|
||||||
|
if( _debugEnabled )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
synchronized( this )
|
||||||
|
{
|
||||||
|
_stepCount++;
|
||||||
|
if( _stepTime > 0 )
|
||||||
|
{
|
||||||
|
wait( (int)_stepTime );
|
||||||
|
/** Can we resume execution or are we expected to wait? */
|
||||||
|
if( _waitUntilNotified )
|
||||||
|
{
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
// We have been notified
|
||||||
|
_waitUntilNotified = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( InterruptedException e )
|
||||||
|
{
|
||||||
|
update("Triangulation was interrupted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( _terminated )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "Triangulation process terminated before completion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
_points.clear();
|
||||||
|
_terminated = false;
|
||||||
|
if( _debug != null )
|
||||||
|
{
|
||||||
|
_debug.clear();
|
||||||
|
}
|
||||||
|
_stepCount=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationMode getTriangulationMode()
|
||||||
|
{
|
||||||
|
return _triangulationMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void waitUntilNotified(boolean b)
|
||||||
|
{
|
||||||
|
_waitUntilNotified = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void terminateTriangulation()
|
||||||
|
{
|
||||||
|
_terminated=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebugEnabled()
|
||||||
|
{
|
||||||
|
return _debugEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void isDebugEnabled( boolean b );
|
||||||
|
|
||||||
|
public A getDebugContext()
|
||||||
|
{
|
||||||
|
return _debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPoints( List<TriangulationPoint> points )
|
||||||
|
{
|
||||||
|
_points.addAll( points );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
public abstract class TriangulationDebugContext
|
||||||
|
{
|
||||||
|
protected TriangulationContext<?> _tcx;
|
||||||
|
|
||||||
|
public TriangulationDebugContext( TriangulationContext<?> tcx )
|
||||||
|
{
|
||||||
|
_tcx = tcx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void clear();
|
||||||
|
}
|
||||||
6
src/org/poly2tri/triangulation/TriangulationMode.java
Normal file
6
src/org/poly2tri/triangulation/TriangulationMode.java
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
public enum TriangulationMode
|
||||||
|
{
|
||||||
|
UNCONSTRAINED,CONSTRAINED,POLYGON;
|
||||||
|
}
|
||||||
112
src/org/poly2tri/triangulation/TriangulationPoint.java
Normal file
112
src/org/poly2tri/triangulation/TriangulationPoint.java
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.primitives.Point;
|
||||||
|
import org.poly2tri.triangulation.delaunay.sweep.DTSweepConstraint;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class TriangulationPoint extends Point
|
||||||
|
{
|
||||||
|
// List of edges this point constitutes an upper ending point (CDT)
|
||||||
|
private ArrayList<DTSweepConstraint> edges;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "[" + getX() + "," + getY() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract double getX();
|
||||||
|
public abstract double getY();
|
||||||
|
public abstract double getZ();
|
||||||
|
|
||||||
|
public abstract float getXf();
|
||||||
|
public abstract float getYf();
|
||||||
|
public abstract float getZf();
|
||||||
|
|
||||||
|
public abstract void set( double x, double y, double z );
|
||||||
|
|
||||||
|
public ArrayList<DTSweepConstraint> getEdges()
|
||||||
|
{
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEdge( DTSweepConstraint e )
|
||||||
|
{
|
||||||
|
if( edges == null )
|
||||||
|
{
|
||||||
|
edges = new ArrayList<DTSweepConstraint>();
|
||||||
|
}
|
||||||
|
edges.add( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEdges()
|
||||||
|
{
|
||||||
|
return edges != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param p - edge destination point
|
||||||
|
* @return the edge from this point to given point
|
||||||
|
*/
|
||||||
|
public DTSweepConstraint getEdge( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
for( DTSweepConstraint c : edges )
|
||||||
|
{
|
||||||
|
if( c.p == p )
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if( obj instanceof TriangulationPoint )
|
||||||
|
{
|
||||||
|
TriangulationPoint p = (TriangulationPoint)obj;
|
||||||
|
return getX() == p.getX() && getY() == p.getY();
|
||||||
|
}
|
||||||
|
return super.equals( obj );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
long bits = Double.doubleToLongBits(getX());
|
||||||
|
bits ^= Double.doubleToLongBits(getY()) * 31;
|
||||||
|
return (((int) bits) ^ ((int) (bits >> 32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
347
src/org/poly2tri/triangulation/TriangulationProcess.java
Normal file
347
src/org/poly2tri/triangulation/TriangulationProcess.java
Normal file
|
|
@ -0,0 +1,347 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
import java.lang.Thread.State;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.Poly2Tri;
|
||||||
|
import org.poly2tri.geometry.polygon.Polygon;
|
||||||
|
import org.poly2tri.geometry.polygon.PolygonSet;
|
||||||
|
import org.poly2tri.triangulation.sets.ConstrainedPointSet;
|
||||||
|
import org.poly2tri.triangulation.sets.PointSet;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Thomas Åhlén, thahlen@gmail.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TriangulationProcess implements Runnable
|
||||||
|
{
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger( TriangulationProcess.class );
|
||||||
|
|
||||||
|
private final TriangulationAlgorithm _algorithm;
|
||||||
|
|
||||||
|
private TriangulationContext<?> _tcx;
|
||||||
|
private Thread _thread;
|
||||||
|
private boolean _isTerminated = false;
|
||||||
|
private int _pointCount = 0;
|
||||||
|
private long _timestamp = 0;
|
||||||
|
private double _triangulationTime = 0;
|
||||||
|
|
||||||
|
private boolean _awaitingTermination;
|
||||||
|
private boolean _restart = false;
|
||||||
|
|
||||||
|
private ArrayList<Triangulatable> _triangulations = new ArrayList<Triangulatable>();
|
||||||
|
|
||||||
|
private ArrayList<TriangulationProcessListener> _listeners = new ArrayList<TriangulationProcessListener>();
|
||||||
|
|
||||||
|
public void addListener( TriangulationProcessListener listener )
|
||||||
|
{
|
||||||
|
_listeners.add( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener( TriangulationProcessListener listener )
|
||||||
|
{
|
||||||
|
_listeners.remove( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearListeners()
|
||||||
|
{
|
||||||
|
_listeners.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify all listeners of this new event
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
private void sendEvent( TriangulationProcessEvent event )
|
||||||
|
{
|
||||||
|
for( TriangulationProcessListener l : _listeners )
|
||||||
|
{
|
||||||
|
l.triangulationEvent( event, _tcx.getTriangulatable() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStepCount()
|
||||||
|
{
|
||||||
|
return _tcx.getStepCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp()
|
||||||
|
{
|
||||||
|
return _timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTriangulationTime()
|
||||||
|
{
|
||||||
|
return _triangulationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses SweepLine algorithm by default
|
||||||
|
* @param algorithm
|
||||||
|
*/
|
||||||
|
public TriangulationProcess()
|
||||||
|
{
|
||||||
|
this( TriangulationAlgorithm.DTSweep );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationProcess( TriangulationAlgorithm algorithm )
|
||||||
|
{
|
||||||
|
_algorithm = algorithm;
|
||||||
|
_tcx = Poly2Tri.createContext( algorithm );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This retriangulates same set as previous triangulation
|
||||||
|
* useful if you want to do consecutive triangulations with
|
||||||
|
* same data. Like when you when you want to do performance
|
||||||
|
* tests.
|
||||||
|
*/
|
||||||
|
// public void triangulate()
|
||||||
|
// {
|
||||||
|
// start();
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triangulate a PointSet with eventual constraints
|
||||||
|
*
|
||||||
|
* @param cps
|
||||||
|
*/
|
||||||
|
public void triangulate( PointSet ps )
|
||||||
|
{
|
||||||
|
_triangulations.clear();
|
||||||
|
_triangulations.add( ps );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triangulate a PointSet with eventual constraints
|
||||||
|
*
|
||||||
|
* @param cps
|
||||||
|
*/
|
||||||
|
public void triangulate( ConstrainedPointSet cps )
|
||||||
|
{
|
||||||
|
_triangulations.clear();
|
||||||
|
_triangulations.add( cps );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triangulate a PolygonSet
|
||||||
|
*
|
||||||
|
* @param ps
|
||||||
|
*/
|
||||||
|
public void triangulate( PolygonSet ps )
|
||||||
|
{
|
||||||
|
_triangulations.clear();
|
||||||
|
_triangulations.addAll( ps.getPolygons() );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triangulate a Polygon
|
||||||
|
*
|
||||||
|
* @param ps
|
||||||
|
*/
|
||||||
|
public void triangulate( Polygon polygon )
|
||||||
|
{
|
||||||
|
_triangulations.clear();
|
||||||
|
_triangulations.add( polygon );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triangulate a List of Triangulatables
|
||||||
|
*
|
||||||
|
* @param ps
|
||||||
|
*/
|
||||||
|
public void triangulate( List<Triangulatable> list )
|
||||||
|
{
|
||||||
|
_triangulations.clear();
|
||||||
|
_triangulations.addAll( list );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void start()
|
||||||
|
{
|
||||||
|
if( _thread == null || _thread.getState() == State.TERMINATED )
|
||||||
|
{
|
||||||
|
_isTerminated = false;
|
||||||
|
_thread = new Thread( this, _algorithm.name() + "." + _tcx.getTriangulationMode() );
|
||||||
|
_thread.start();
|
||||||
|
sendEvent( TriangulationProcessEvent.Started );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Triangulation already running. Terminate it so we can start a new
|
||||||
|
shutdown();
|
||||||
|
_restart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWaiting()
|
||||||
|
{
|
||||||
|
if( _thread != null && _thread.getState() == State.WAITING )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
_pointCount=0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
long time = System.nanoTime();
|
||||||
|
for( Triangulatable t : _triangulations )
|
||||||
|
{
|
||||||
|
_tcx.clear();
|
||||||
|
_tcx.prepareTriangulation( t );
|
||||||
|
_pointCount += _tcx._points.size();
|
||||||
|
Poly2Tri.triangulate( _tcx );
|
||||||
|
}
|
||||||
|
_triangulationTime = ( System.nanoTime() - time ) / 1e6;
|
||||||
|
logger.info( "Triangulation of {} points [{}ms]", _pointCount, _triangulationTime );
|
||||||
|
sendEvent( TriangulationProcessEvent.Done );
|
||||||
|
}
|
||||||
|
catch( RuntimeException e )
|
||||||
|
{
|
||||||
|
if( _awaitingTermination )
|
||||||
|
{
|
||||||
|
_awaitingTermination = false;
|
||||||
|
logger.info( "Thread[{}] : {}", _thread.getName(), e.getMessage() );
|
||||||
|
sendEvent( TriangulationProcessEvent.Aborted );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
sendEvent( TriangulationProcessEvent.Failed );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( Exception e )
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
logger.info( "Triangulation exception {}", e.getMessage() );
|
||||||
|
sendEvent( TriangulationProcessEvent.Failed );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_timestamp = System.currentTimeMillis();
|
||||||
|
_isTerminated = true;
|
||||||
|
_thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autostart a new triangulation?
|
||||||
|
if( _restart )
|
||||||
|
{
|
||||||
|
_restart = false;
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resume()
|
||||||
|
{
|
||||||
|
if( _thread != null )
|
||||||
|
{
|
||||||
|
// Only force a resume when process is waiting for a notification
|
||||||
|
if( _thread.getState() == State.WAITING )
|
||||||
|
{
|
||||||
|
synchronized( _tcx )
|
||||||
|
{
|
||||||
|
_tcx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( _thread.getState() == State.TIMED_WAITING )
|
||||||
|
{
|
||||||
|
_tcx.waitUntilNotified( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown()
|
||||||
|
{
|
||||||
|
_awaitingTermination = true;
|
||||||
|
_tcx.terminateTriangulation();
|
||||||
|
resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationContext<?> getContext()
|
||||||
|
{
|
||||||
|
return _tcx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDone()
|
||||||
|
{
|
||||||
|
return _isTerminated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestRead()
|
||||||
|
{
|
||||||
|
_tcx.waitUntilNotified( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReadable()
|
||||||
|
{
|
||||||
|
if( _thread == null )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
synchronized( _thread )
|
||||||
|
{
|
||||||
|
if( _thread.getState() == State.WAITING )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if( _thread.getState() == State.TIMED_WAITING )
|
||||||
|
{
|
||||||
|
// Make sure that it stays readable
|
||||||
|
_tcx.waitUntilNotified( true );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPointCount()
|
||||||
|
{
|
||||||
|
return _pointCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
public enum TriangulationProcessEvent
|
||||||
|
{
|
||||||
|
Started,Waiting,Failed,Aborted,Done
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
public interface TriangulationProcessListener
|
||||||
|
{
|
||||||
|
public void triangulationEvent(TriangulationProcessEvent e, Triangulatable unit);
|
||||||
|
}
|
||||||
213
src/org/poly2tri/triangulation/TriangulationUtil.java
Normal file
213
src/org/poly2tri/triangulation/TriangulationUtil.java
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/package org.poly2tri.triangulation;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Åhlén, thahlen@gmail.com
|
||||||
|
*/
|
||||||
|
public class TriangulationUtil
|
||||||
|
{
|
||||||
|
public final static double EPSILON = 1e-12;
|
||||||
|
|
||||||
|
// Returns triangle circumcircle point and radius
|
||||||
|
// public static Tuple2<TPoint, Double> circumCircle( TPoint a, TPoint b, TPoint c )
|
||||||
|
// {
|
||||||
|
// double A = det( a, b, c );
|
||||||
|
// double C = detC( a, b, c );
|
||||||
|
//
|
||||||
|
// double sa = a.getX() * a.getX() + a.getY() * a.getY();
|
||||||
|
// double sb = b.getX() * b.getX() + b.getY() * b.getY();
|
||||||
|
// double sc = c.getX() * c.getX() + c.getY() * c.getY();
|
||||||
|
//
|
||||||
|
// TPoint bx1 = new TPoint( sa, a.getY() );
|
||||||
|
// TPoint bx2 = new TPoint( sb, b.getY() );
|
||||||
|
// TPoint bx3 = new TPoint( sc, c.getY() );
|
||||||
|
// double bx = det( bx1, bx2, bx3 );
|
||||||
|
//
|
||||||
|
// TPoint by1 = new TPoint( sa, a.getX() );
|
||||||
|
// TPoint by2 = new TPoint( sb, b.getX() );
|
||||||
|
// TPoint by3 = new TPoint( sc, c.getX() );
|
||||||
|
// double by = det( by1, by2, by3 );
|
||||||
|
//
|
||||||
|
// double x = bx / ( 2 * A );
|
||||||
|
// double y = by / ( 2 * A );
|
||||||
|
//
|
||||||
|
// TPoint center = new TPoint( x, y );
|
||||||
|
// double radius = Math.sqrt( bx * bx + by * by - 4 * A * C ) / ( 2 * Math.abs( A ) );
|
||||||
|
//
|
||||||
|
// return new Tuple2<TPoint, Double>( center, radius );
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Requirement</b>:<br>
|
||||||
|
* 1. a,b and c form a triangle.<br>
|
||||||
|
* 2. a and d is know to be on opposite side of bc<br>
|
||||||
|
* <pre>
|
||||||
|
* a
|
||||||
|
* +
|
||||||
|
* / \
|
||||||
|
* / \
|
||||||
|
* b/ \c
|
||||||
|
* +-------+
|
||||||
|
* / B \
|
||||||
|
* / \
|
||||||
|
* </pre>
|
||||||
|
* <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by
|
||||||
|
* a,b and c<br>
|
||||||
|
* d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW<br>
|
||||||
|
* This preknowledge gives us a way to optimize the incircle test
|
||||||
|
* @param a - triangle point, opposite d
|
||||||
|
* @param b - triangle point
|
||||||
|
* @param c - triangle point
|
||||||
|
* @param d - point opposite a
|
||||||
|
* @return true if d is inside circle, false if on circle edge
|
||||||
|
*/
|
||||||
|
public static boolean smartIncircle( final TriangulationPoint pa,
|
||||||
|
final TriangulationPoint pb,
|
||||||
|
final TriangulationPoint pc,
|
||||||
|
final TriangulationPoint pd )
|
||||||
|
{
|
||||||
|
final double pdx = pd.getX();
|
||||||
|
final double pdy = pd.getY();
|
||||||
|
final double adx = pa.getX() - pdx;
|
||||||
|
final double ady = pa.getY() - pdy;
|
||||||
|
final double bdx = pb.getX() - pdx;
|
||||||
|
final double bdy = pb.getY() - pdy;
|
||||||
|
|
||||||
|
final double adxbdy = adx * bdy;
|
||||||
|
final double bdxady = bdx * ady;
|
||||||
|
final double oabd = adxbdy - bdxady;
|
||||||
|
// oabd = orient2d(pa,pb,pd);
|
||||||
|
if( oabd <= 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final double cdx = pc.getX() - pdx;
|
||||||
|
final double cdy = pc.getY() - pdy;
|
||||||
|
|
||||||
|
final double cdxady = cdx * ady;
|
||||||
|
final double adxcdy = adx * cdy;
|
||||||
|
final double ocad = cdxady - adxcdy;
|
||||||
|
// ocad = orient2d(pc,pa,pd);
|
||||||
|
if( ocad <= 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final double bdxcdy = bdx * cdy;
|
||||||
|
final double cdxbdy = cdx * bdy;
|
||||||
|
|
||||||
|
final double alift = adx * adx + ady * ady;
|
||||||
|
final double blift = bdx * bdx + bdy * bdy;
|
||||||
|
final double clift = cdx * cdx + cdy * cdy;
|
||||||
|
|
||||||
|
final double det = alift * ( bdxcdy - cdxbdy ) + blift * ocad + clift * oabd;
|
||||||
|
|
||||||
|
return det > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see smartIncircle
|
||||||
|
* @param pa
|
||||||
|
* @param pb
|
||||||
|
* @param pc
|
||||||
|
* @param pd
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean inScanArea( final TriangulationPoint pa,
|
||||||
|
final TriangulationPoint pb,
|
||||||
|
final TriangulationPoint pc,
|
||||||
|
final TriangulationPoint pd )
|
||||||
|
{
|
||||||
|
final double pdx = pd.getX();
|
||||||
|
final double pdy = pd.getY();
|
||||||
|
final double adx = pa.getX() - pdx;
|
||||||
|
final double ady = pa.getY() - pdy;
|
||||||
|
final double bdx = pb.getX() - pdx;
|
||||||
|
final double bdy = pb.getY() - pdy;
|
||||||
|
|
||||||
|
final double adxbdy = adx * bdy;
|
||||||
|
final double bdxady = bdx * ady;
|
||||||
|
final double oabd = adxbdy - bdxady;
|
||||||
|
// oabd = orient2d(pa,pb,pd);
|
||||||
|
if( oabd <= 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final double cdx = pc.getX() - pdx;
|
||||||
|
final double cdy = pc.getY() - pdy;
|
||||||
|
|
||||||
|
final double cdxady = cdx * ady;
|
||||||
|
final double adxcdy = adx * cdy;
|
||||||
|
final double ocad = cdxady - adxcdy;
|
||||||
|
// ocad = orient2d(pc,pa,pd);
|
||||||
|
if( ocad <= 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forumla to calculate signed area<br>
|
||||||
|
* Positive if CCW<br>
|
||||||
|
* Negative if CW<br>
|
||||||
|
* 0 if collinear<br>
|
||||||
|
* <pre>
|
||||||
|
* A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
|
||||||
|
* = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public static Orientation orient2d( TriangulationPoint pa,
|
||||||
|
TriangulationPoint pb,
|
||||||
|
TriangulationPoint pc )
|
||||||
|
{
|
||||||
|
double detleft = ( pa.getX() - pc.getX() ) * ( pb.getY() - pc.getY() );
|
||||||
|
double detright = ( pa.getY() - pc.getY() ) * ( pb.getX() - pc.getX() );
|
||||||
|
double val = detleft - detright;
|
||||||
|
if( val > -EPSILON && val < EPSILON )
|
||||||
|
{
|
||||||
|
return Orientation.Collinear;
|
||||||
|
}
|
||||||
|
else if( val > 0 )
|
||||||
|
{
|
||||||
|
return Orientation.CCW;
|
||||||
|
}
|
||||||
|
return Orientation.CW;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Orientation
|
||||||
|
{
|
||||||
|
CW,CCW,Collinear;
|
||||||
|
}
|
||||||
|
}
|
||||||
693
src/org/poly2tri/triangulation/delaunay/DelaunayTriangle.java
Normal file
693
src/org/poly2tri/triangulation/delaunay/DelaunayTriangle.java
Normal file
|
|
@ -0,0 +1,693 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.delaunay;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.sweep.DTSweepConstraint;
|
||||||
|
import org.poly2tri.triangulation.point.TPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public class DelaunayTriangle
|
||||||
|
{
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger( DelaunayTriangle.class );
|
||||||
|
|
||||||
|
/** Neighbor pointers */
|
||||||
|
public final DelaunayTriangle[] neighbors = new DelaunayTriangle[3];
|
||||||
|
/** Flags to determine if an edge is a Constrained edge */
|
||||||
|
public final boolean[] cEdge = new boolean[] { false, false, false };
|
||||||
|
/** Flags to determine if an edge is a Delauney edge */
|
||||||
|
public final boolean[] dEdge = new boolean[] { false, false, false };
|
||||||
|
/** Has this triangle been marked as an interior triangle? */
|
||||||
|
protected boolean interior = false;
|
||||||
|
|
||||||
|
public final TriangulationPoint[] points = new TriangulationPoint[3];
|
||||||
|
|
||||||
|
public DelaunayTriangle( TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3 )
|
||||||
|
{
|
||||||
|
points[0] = p1;
|
||||||
|
points[1] = p2;
|
||||||
|
points[2] = p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int index( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if( p == points[2] )
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Calling index with a point that doesn't exist in triangle");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int indexCW( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
int index = index(p);
|
||||||
|
switch( index )
|
||||||
|
{
|
||||||
|
case 0: return 2;
|
||||||
|
case 1: return 0;
|
||||||
|
default: return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int indexCCW( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
int index = index(p);
|
||||||
|
switch( index )
|
||||||
|
{
|
||||||
|
case 0: return 1;
|
||||||
|
case 1: return 2;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
return ( p == points[0] || p == points[1] || p == points[2] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains( DTSweepConstraint e )
|
||||||
|
{
|
||||||
|
return ( contains( e.p ) && contains( e.q ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains( TriangulationPoint p, TriangulationPoint q )
|
||||||
|
{
|
||||||
|
return ( contains( p ) && contains( q ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update neighbor pointers
|
||||||
|
private void markNeighbor( TriangulationPoint p1,
|
||||||
|
TriangulationPoint p2,
|
||||||
|
DelaunayTriangle t )
|
||||||
|
{
|
||||||
|
if( ( p1 == points[2] && p2 == points[1] ) || ( p1 == points[1] && p2 == points[2] ) )
|
||||||
|
{
|
||||||
|
neighbors[0] = t;
|
||||||
|
}
|
||||||
|
else if( ( p1 == points[0] && p2 == points[2] ) || ( p1 == points[2] && p2 == points[0] ) )
|
||||||
|
{
|
||||||
|
neighbors[1] = t;
|
||||||
|
}
|
||||||
|
else if( ( p1 == points[0] && p2 == points[1] ) || ( p1 == points[1] && p2 == points[0] ) )
|
||||||
|
{
|
||||||
|
neighbors[2] = t;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.error( "Neighbor error, please report!" );
|
||||||
|
// throw new Exception("Neighbor error, please report!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exhaustive search to update neighbor pointers */
|
||||||
|
public void markNeighbor( DelaunayTriangle t )
|
||||||
|
{
|
||||||
|
if( t.contains( points[1], points[2] ) )
|
||||||
|
{
|
||||||
|
neighbors[0] = t;
|
||||||
|
t.markNeighbor( points[1], points[2], this );
|
||||||
|
}
|
||||||
|
else if( t.contains( points[0], points[2] ) )
|
||||||
|
{
|
||||||
|
neighbors[1] = t;
|
||||||
|
t.markNeighbor( points[0], points[2], this );
|
||||||
|
}
|
||||||
|
else if( t.contains( points[0], points[1] ) )
|
||||||
|
{
|
||||||
|
neighbors[2] = t;
|
||||||
|
t.markNeighbor( points[0], points[1], this );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.error( "markNeighbor failed" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearNeighbors()
|
||||||
|
{
|
||||||
|
neighbors[0] = neighbors[1] = neighbors[2] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearNeighbor( DelaunayTriangle triangle )
|
||||||
|
{
|
||||||
|
if( neighbors[0] == triangle )
|
||||||
|
{
|
||||||
|
neighbors[0] = null;
|
||||||
|
}
|
||||||
|
else if( neighbors[1] == triangle )
|
||||||
|
{
|
||||||
|
neighbors[1] = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
neighbors[2] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all references to all other triangles and points
|
||||||
|
*/
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
DelaunayTriangle t;
|
||||||
|
for( int i=0; i<3; i++ )
|
||||||
|
{
|
||||||
|
t = neighbors[i];
|
||||||
|
if( t != null )
|
||||||
|
{
|
||||||
|
t.clearNeighbor( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearNeighbors();
|
||||||
|
points[0]=points[1]=points[2]=null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param t - opposite triangle
|
||||||
|
* @param p - the point in t that isn't shared between the triangles
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TriangulationPoint oppositePoint( DelaunayTriangle t, TriangulationPoint p )
|
||||||
|
{
|
||||||
|
assert t != this : "self-pointer error";
|
||||||
|
return pointCW( t.pointCW(p) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// The neighbor clockwise to given point
|
||||||
|
public DelaunayTriangle neighborCW( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
if( point == points[0] )
|
||||||
|
{
|
||||||
|
return neighbors[1];
|
||||||
|
}
|
||||||
|
else if( point == points[1] )
|
||||||
|
{
|
||||||
|
return neighbors[2];
|
||||||
|
}
|
||||||
|
return neighbors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The neighbor counter-clockwise to given point
|
||||||
|
public DelaunayTriangle neighborCCW( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
if( point == points[0] )
|
||||||
|
{
|
||||||
|
return neighbors[2];
|
||||||
|
}
|
||||||
|
else if( point == points[1] )
|
||||||
|
{
|
||||||
|
return neighbors[0];
|
||||||
|
}
|
||||||
|
return neighbors[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The neighbor across to given point
|
||||||
|
public DelaunayTriangle neighborAcross( TriangulationPoint opoint )
|
||||||
|
{
|
||||||
|
if( opoint == points[0] )
|
||||||
|
{
|
||||||
|
return neighbors[0];
|
||||||
|
}
|
||||||
|
else if( opoint == points[1] )
|
||||||
|
{
|
||||||
|
return neighbors[1];
|
||||||
|
}
|
||||||
|
return neighbors[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The point counter-clockwise to given point
|
||||||
|
public TriangulationPoint pointCCW( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
if( point == points[0] )
|
||||||
|
{
|
||||||
|
return points[1];
|
||||||
|
}
|
||||||
|
else if( point == points[1] )
|
||||||
|
{
|
||||||
|
return points[2];
|
||||||
|
}
|
||||||
|
else if( point == points[2] )
|
||||||
|
{
|
||||||
|
return points[0];
|
||||||
|
}
|
||||||
|
logger.error( "point location error" );
|
||||||
|
throw new RuntimeException("[FIXME] point location error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The point counter-clockwise to given point
|
||||||
|
public TriangulationPoint pointCW( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
if( point == points[0] )
|
||||||
|
{
|
||||||
|
return points[2];
|
||||||
|
}
|
||||||
|
else if( point == points[1] )
|
||||||
|
{
|
||||||
|
return points[0];
|
||||||
|
}
|
||||||
|
else if( point == points[2] )
|
||||||
|
{
|
||||||
|
return points[1];
|
||||||
|
}
|
||||||
|
logger.error( "point location error" );
|
||||||
|
throw new RuntimeException("[FIXME] point location error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legalize triangle by rotating clockwise around oPoint
|
||||||
|
public void legalize( TriangulationPoint oPoint, TriangulationPoint nPoint )
|
||||||
|
{
|
||||||
|
if( oPoint == points[0] )
|
||||||
|
{
|
||||||
|
points[1] = points[0];
|
||||||
|
points[0] = points[2];
|
||||||
|
points[2] = nPoint;
|
||||||
|
}
|
||||||
|
else if( oPoint == points[1] )
|
||||||
|
{
|
||||||
|
points[2] = points[1];
|
||||||
|
points[1] = points[0];
|
||||||
|
points[0] = nPoint;
|
||||||
|
}
|
||||||
|
else if( oPoint == points[2] )
|
||||||
|
{
|
||||||
|
points[0] = points[2];
|
||||||
|
points[2] = points[1];
|
||||||
|
points[1] = nPoint;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.error( "legalization error" );
|
||||||
|
throw new RuntimeException("legalization bug");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printDebug()
|
||||||
|
{
|
||||||
|
System.out.println( points[0] + "," + points[1] + "," + points[2] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize edge marking
|
||||||
|
public void markNeighborEdges()
|
||||||
|
{
|
||||||
|
for( int i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
if( cEdge[i] )
|
||||||
|
{
|
||||||
|
switch( i )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if( neighbors[0] != null )
|
||||||
|
neighbors[0].markConstrainedEdge( points[1], points[2] );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if( neighbors[1] != null )
|
||||||
|
neighbors[1].markConstrainedEdge( points[0], points[2] );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if( neighbors[2] != null )
|
||||||
|
neighbors[2].markConstrainedEdge( points[0], points[1] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markEdge( DelaunayTriangle triangle )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
if( cEdge[i] )
|
||||||
|
{
|
||||||
|
switch( i )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
triangle.markConstrainedEdge( points[1], points[2] );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
triangle.markConstrainedEdge( points[0], points[2] );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
triangle.markConstrainedEdge( points[0], points[1] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markEdge( ArrayList<DelaunayTriangle> tList )
|
||||||
|
{
|
||||||
|
|
||||||
|
for( DelaunayTriangle t : tList )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
if( t.cEdge[i] )
|
||||||
|
{
|
||||||
|
switch( i )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
markConstrainedEdge( t.points[1], t.points[2] );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
markConstrainedEdge( t.points[0], t.points[2] );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
markConstrainedEdge( t.points[0], t.points[1] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markConstrainedEdge( int index )
|
||||||
|
{
|
||||||
|
cEdge[index] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markConstrainedEdge( DTSweepConstraint edge )
|
||||||
|
{
|
||||||
|
markConstrainedEdge( edge.p, edge.q );
|
||||||
|
if( ( edge.q == points[0] && edge.p == points[1] )
|
||||||
|
|| ( edge.q == points[1] && edge.p == points[0] ) )
|
||||||
|
{
|
||||||
|
cEdge[2] = true;
|
||||||
|
}
|
||||||
|
else if( ( edge.q == points[0] && edge.p == points[2] )
|
||||||
|
|| ( edge.q == points[2] && edge.p == points[0] ) )
|
||||||
|
{
|
||||||
|
cEdge[1] = true;
|
||||||
|
}
|
||||||
|
else if( ( edge.q == points[1] && edge.p == points[2] )
|
||||||
|
|| ( edge.q == points[2] && edge.p == points[1] ) )
|
||||||
|
{
|
||||||
|
cEdge[0] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark edge as constrained
|
||||||
|
public void markConstrainedEdge( TriangulationPoint p, TriangulationPoint q )
|
||||||
|
{
|
||||||
|
if( ( q == points[0] && p == points[1] ) || ( q == points[1] && p == points[0] ) )
|
||||||
|
{
|
||||||
|
cEdge[2] = true;
|
||||||
|
}
|
||||||
|
else if( ( q == points[0] && p == points[2] ) || ( q == points[2] && p == points[0] ) )
|
||||||
|
{
|
||||||
|
cEdge[1] = true;
|
||||||
|
}
|
||||||
|
else if( ( q == points[1] && p == points[2] ) || ( q == points[2] && p == points[1] ) )
|
||||||
|
{
|
||||||
|
cEdge[0] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double area()
|
||||||
|
{
|
||||||
|
double a = (points[0].getX() - points[2].getX())*(points[1].getY() - points[0].getY());
|
||||||
|
double b = (points[0].getX() - points[1].getX())*(points[2].getY() - points[0].getY());
|
||||||
|
|
||||||
|
return 0.5*Math.abs( a - b );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TPoint centroid()
|
||||||
|
{
|
||||||
|
double cx = ( points[0].getX() + points[1].getX() + points[2].getX() ) / 3d;
|
||||||
|
double cy = ( points[0].getY() + points[1].getY() + points[2].getY() ) / 3d;
|
||||||
|
return new TPoint( cx, cy );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the neighbor that share this edge
|
||||||
|
*
|
||||||
|
* @param constrainedEdge
|
||||||
|
* @return index of the shared edge or -1 if edge isn't shared
|
||||||
|
*/
|
||||||
|
public int edgeIndex( TriangulationPoint p1, TriangulationPoint p2 )
|
||||||
|
{
|
||||||
|
if( points[0] == p1 )
|
||||||
|
{
|
||||||
|
if( points[1] == p2 )
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else if( points[2] == p2 )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( points[1] == p1 )
|
||||||
|
{
|
||||||
|
if( points[2] == p2 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if( points[0] == p2 )
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( points[2] == p1 )
|
||||||
|
{
|
||||||
|
if( points[0] == p2 )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if( points[1] == p2 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getConstrainedEdgeCCW( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return cEdge[2];
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return cEdge[0];
|
||||||
|
}
|
||||||
|
return cEdge[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getConstrainedEdgeCW( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return cEdge[1];
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return cEdge[2];
|
||||||
|
}
|
||||||
|
return cEdge[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getConstrainedEdgeAcross( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return cEdge[0];
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return cEdge[1];
|
||||||
|
}
|
||||||
|
return cEdge[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstrainedEdgeCCW( TriangulationPoint p, boolean ce )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
cEdge[2] = ce;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
cEdge[0] = ce;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cEdge[1] = ce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstrainedEdgeCW( TriangulationPoint p, boolean ce )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
cEdge[1] = ce;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
cEdge[2] = ce;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cEdge[0] = ce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstrainedEdgeAcross( TriangulationPoint p, boolean ce )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
cEdge[0] = ce;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
cEdge[1] = ce;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cEdge[2] = ce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getDelunayEdgeCCW( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return dEdge[2];
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return dEdge[0];
|
||||||
|
}
|
||||||
|
return dEdge[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getDelunayEdgeCW( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return dEdge[1];
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return dEdge[2];
|
||||||
|
}
|
||||||
|
return dEdge[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getDelunayEdgeAcross( TriangulationPoint p )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
return dEdge[0];
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
return dEdge[1];
|
||||||
|
}
|
||||||
|
return dEdge[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelunayEdgeCCW( TriangulationPoint p, boolean e )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
dEdge[2] = e;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
dEdge[0] = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dEdge[1] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelunayEdgeCW( TriangulationPoint p, boolean e )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
dEdge[1] = e;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
dEdge[2] = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dEdge[0] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelunayEdgeAcross( TriangulationPoint p, boolean e )
|
||||||
|
{
|
||||||
|
if( p == points[0] )
|
||||||
|
{
|
||||||
|
dEdge[0] = e;
|
||||||
|
}
|
||||||
|
else if( p == points[1] )
|
||||||
|
{
|
||||||
|
dEdge[1] = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dEdge[2] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearDelunayEdges()
|
||||||
|
{
|
||||||
|
dEdge[0] = false;
|
||||||
|
dEdge[1] = false;
|
||||||
|
dEdge[2] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterior()
|
||||||
|
{
|
||||||
|
return interior;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void isInterior( boolean b )
|
||||||
|
{
|
||||||
|
interior = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Åhlen (thahlen@gmail.com)
|
||||||
|
*/
|
||||||
|
public class AdvancingFront
|
||||||
|
{
|
||||||
|
public AdvancingFrontNode head;
|
||||||
|
public AdvancingFrontNode tail;
|
||||||
|
protected AdvancingFrontNode search;
|
||||||
|
|
||||||
|
public AdvancingFront( AdvancingFrontNode head, AdvancingFrontNode tail )
|
||||||
|
{
|
||||||
|
this.head = head;
|
||||||
|
this.tail = tail;
|
||||||
|
this.search = head;
|
||||||
|
addNode( head );
|
||||||
|
addNode( tail );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNode( AdvancingFrontNode node )
|
||||||
|
{
|
||||||
|
// _searchTree.put( node.key, node );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeNode( AdvancingFrontNode node )
|
||||||
|
{
|
||||||
|
// _searchTree.delete( node.key );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
AdvancingFrontNode node = head;
|
||||||
|
while( node != tail )
|
||||||
|
{
|
||||||
|
sb.append( node.point.getX() ).append( "->" );
|
||||||
|
node = node.next;
|
||||||
|
}
|
||||||
|
sb.append( tail.point.getX() );
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AdvancingFrontNode findSearchNode( double x )
|
||||||
|
{
|
||||||
|
// TODO: implement BST index
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We use a balancing tree to locate a node smaller or equal to
|
||||||
|
* given key value
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AdvancingFrontNode locateNode( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
return locateNode( point.getX() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private AdvancingFrontNode locateNode( double x )
|
||||||
|
{
|
||||||
|
AdvancingFrontNode node = findSearchNode(x);
|
||||||
|
if( x < node.value )
|
||||||
|
{
|
||||||
|
while( (node = node.prev) != null )
|
||||||
|
{
|
||||||
|
if( x >= node.value )
|
||||||
|
{
|
||||||
|
search = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while( (node = node.next) != null )
|
||||||
|
{
|
||||||
|
if( x < node.value )
|
||||||
|
{
|
||||||
|
search = node.prev;
|
||||||
|
return node.prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation will use simple node traversal algorithm to find
|
||||||
|
* a point on the front
|
||||||
|
*
|
||||||
|
* @param point
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AdvancingFrontNode locatePoint( final TriangulationPoint point )
|
||||||
|
{
|
||||||
|
final double px = point.getX();
|
||||||
|
AdvancingFrontNode node = findSearchNode(px);
|
||||||
|
final double nx = node.point.getX();
|
||||||
|
|
||||||
|
if( px == nx )
|
||||||
|
{
|
||||||
|
if( point != node.point )
|
||||||
|
{
|
||||||
|
// We might have two nodes with same x value for a short time
|
||||||
|
if( point == node.prev.point )
|
||||||
|
{
|
||||||
|
node = node.prev;
|
||||||
|
}
|
||||||
|
else if( point == node.next.point )
|
||||||
|
{
|
||||||
|
node = node.next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "Failed to find Node for given afront point");
|
||||||
|
// node = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( px < nx )
|
||||||
|
{
|
||||||
|
while( (node = node.prev) != null )
|
||||||
|
{
|
||||||
|
if( point == node.point )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while( (node = node.next) != null )
|
||||||
|
{
|
||||||
|
if( point == node.point )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
search = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
public class AdvancingFrontIndex<A>
|
||||||
|
{
|
||||||
|
double _min,_max;
|
||||||
|
IndexNode<A> _root;
|
||||||
|
|
||||||
|
public AdvancingFrontIndex( double min, double max, int depth )
|
||||||
|
{
|
||||||
|
if( depth > 5 ) depth = 5;
|
||||||
|
_root = createIndex( depth );
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndexNode<A> createIndex( int n )
|
||||||
|
{
|
||||||
|
IndexNode<A> node = null;
|
||||||
|
if( n > 0 )
|
||||||
|
{
|
||||||
|
node = new IndexNode<A>();
|
||||||
|
node.bigger = createIndex( n-1 );
|
||||||
|
node.smaller = createIndex( n-1 );
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A fetchAndRemoveIndex( A key )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A fetchAndInsertIndex( A key )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
class IndexNode<A>
|
||||||
|
{
|
||||||
|
A value;
|
||||||
|
IndexNode<A> smaller;
|
||||||
|
IndexNode<A> bigger;
|
||||||
|
double range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class AdvancingFrontNode
|
||||||
|
{
|
||||||
|
protected AdvancingFrontNode next = null;
|
||||||
|
protected AdvancingFrontNode prev = null;
|
||||||
|
|
||||||
|
protected final Double key; // XXX: BST
|
||||||
|
protected final double value;
|
||||||
|
protected final TriangulationPoint point;
|
||||||
|
protected DelaunayTriangle triangle;
|
||||||
|
|
||||||
|
public AdvancingFrontNode( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
this.point = point;
|
||||||
|
value = point.getX();
|
||||||
|
key = Double.valueOf( value ); // XXX: BST
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdvancingFrontNode getNext()
|
||||||
|
{
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdvancingFrontNode getPrevious()
|
||||||
|
{
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationPoint getPoint()
|
||||||
|
{
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelaunayTriangle getTriangle()
|
||||||
|
{
|
||||||
|
return triangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext()
|
||||||
|
{
|
||||||
|
return next != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPrevious()
|
||||||
|
{
|
||||||
|
return prev != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
1298
src/org/poly2tri/triangulation/delaunay/sweep/DTSweep.java
Normal file
1298
src/org/poly2tri/triangulation/delaunay/sweep/DTSweep.java
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,106 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationConstraint;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Thomas Åhlén, thahlen@gmail.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DTSweepConstraint extends TriangulationConstraint
|
||||||
|
{
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger( DTSweepConstraint.class );
|
||||||
|
|
||||||
|
public TriangulationPoint p;
|
||||||
|
public TriangulationPoint q;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give two points in any order. Will always be ordered so
|
||||||
|
* that q.y > p.y and q.x > p.x if same y value
|
||||||
|
*
|
||||||
|
* @param p1
|
||||||
|
* @param p2
|
||||||
|
*/
|
||||||
|
public DTSweepConstraint( TriangulationPoint p1, TriangulationPoint p2 )
|
||||||
|
// throws DuplicatePointException
|
||||||
|
{
|
||||||
|
p = p1;
|
||||||
|
q = p2;
|
||||||
|
if( p1.getY() > p2.getY() )
|
||||||
|
{
|
||||||
|
q = p1;
|
||||||
|
p = p2;
|
||||||
|
}
|
||||||
|
else if( p1.getY() == p2.getY() )
|
||||||
|
{
|
||||||
|
if( p1.getX() > p2.getX() )
|
||||||
|
{
|
||||||
|
q = p1;
|
||||||
|
p = p2;
|
||||||
|
}
|
||||||
|
else if( p1.getX() == p2.getX() )
|
||||||
|
{
|
||||||
|
logger.info( "Failed to create constraint {}={}", p1, p2 );
|
||||||
|
// throw new DuplicatePointException( p1 + "=" + p2 );
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q.addEdge(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public TPoint intersect( TPoint a, TPoint b )
|
||||||
|
// {
|
||||||
|
// double pqx,pqy,bax,bay,t;
|
||||||
|
//
|
||||||
|
// pqx = p.getX()-q.getX();
|
||||||
|
// pqy = p.getY()-q.getY();
|
||||||
|
// t = pqy*(a.getX()-q.getX()) - pqx*(a.getY()-q.getY() );
|
||||||
|
// t /= pqx*(b.getY()-a.getY()) - pqy*(b.getX()-a.getX());
|
||||||
|
// bax = t*(b.getX()-a.getX()) + a.getX();
|
||||||
|
// bay = t*(b.getY()-a.getY()) + a.getY();
|
||||||
|
// return new TPoint( bax, bay );
|
||||||
|
// }
|
||||||
|
|
||||||
|
public TriangulationPoint getP()
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationPoint getQ()
|
||||||
|
{
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.Triangulatable;
|
||||||
|
import org.poly2tri.triangulation.TriangulationAlgorithm;
|
||||||
|
import org.poly2tri.triangulation.TriangulationConstraint;
|
||||||
|
import org.poly2tri.triangulation.TriangulationContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
import org.poly2tri.triangulation.point.TPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Thomas Åhlén, thahlen@gmail.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DTSweepContext extends TriangulationContext<DTSweepDebugContext>
|
||||||
|
{
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger( DTSweepContext.class );
|
||||||
|
|
||||||
|
// Inital triangle factor, seed triangle will extend 30% of
|
||||||
|
// PointSet width to both left and right.
|
||||||
|
private final float ALPHA = 0.3f;
|
||||||
|
|
||||||
|
/** Advancing front **/
|
||||||
|
protected AdvancingFront aFront;
|
||||||
|
/** head point used with advancing front */
|
||||||
|
private TriangulationPoint _head;
|
||||||
|
/** tail point used with advancing front */
|
||||||
|
private TriangulationPoint _tail;
|
||||||
|
protected Basin basin = new Basin();
|
||||||
|
protected EdgeEvent edgeEvent = new EdgeEvent();
|
||||||
|
|
||||||
|
private DTSweepPointComparator _comparator = new DTSweepPointComparator();
|
||||||
|
|
||||||
|
public DTSweepContext()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void isDebugEnabled( boolean b )
|
||||||
|
{
|
||||||
|
if( b )
|
||||||
|
{
|
||||||
|
if( _debug == null )
|
||||||
|
{
|
||||||
|
_debug = new DTSweepDebugContext(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_debugEnabled = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFromList( DelaunayTriangle triangle )
|
||||||
|
{
|
||||||
|
_triList.remove( triangle );
|
||||||
|
// TODO: remove all neighbor pointers to this triangle
|
||||||
|
// for( int i=0; i<3; i++ )
|
||||||
|
// {
|
||||||
|
// if( triangle.neighbors[i] != null )
|
||||||
|
// {
|
||||||
|
// triangle.neighbors[i].clearNeighbor( triangle );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// triangle.clearNeighbors();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void meshClean(DelaunayTriangle triangle)
|
||||||
|
{
|
||||||
|
DelaunayTriangle t1,t2;
|
||||||
|
if( triangle != null )
|
||||||
|
{
|
||||||
|
ArrayDeque<DelaunayTriangle> deque = new ArrayDeque<DelaunayTriangle>();
|
||||||
|
deque.addFirst(triangle);
|
||||||
|
triangle.isInterior(true);
|
||||||
|
|
||||||
|
while( !deque.isEmpty() )
|
||||||
|
{
|
||||||
|
t1 = deque.removeFirst();
|
||||||
|
_triUnit.addTriangle( t1 );
|
||||||
|
for( int i=0; i<3; ++i )
|
||||||
|
{
|
||||||
|
if( !t1.cEdge[i] )
|
||||||
|
{
|
||||||
|
t2 = t1.neighbors[i];
|
||||||
|
if( t2 != null && !t2.isInterior() )
|
||||||
|
{
|
||||||
|
t2.isInterior(true);
|
||||||
|
deque.addLast(t2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
super.clear();
|
||||||
|
_triList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdvancingFront getAdvancingFront()
|
||||||
|
{
|
||||||
|
return aFront;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHead( TriangulationPoint p1 ) { _head = p1; }
|
||||||
|
public TriangulationPoint getHead() { return _head; }
|
||||||
|
|
||||||
|
public void setTail( TriangulationPoint p1 ) { _tail = p1; }
|
||||||
|
public TriangulationPoint getTail() { return _tail; }
|
||||||
|
|
||||||
|
public void addNode( AdvancingFrontNode node )
|
||||||
|
{
|
||||||
|
// System.out.println( "add:" + node.key + ":" + System.identityHashCode(node.key));
|
||||||
|
// m_nodeTree.put( node.getKey(), node );
|
||||||
|
aFront.addNode( node );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeNode( AdvancingFrontNode node )
|
||||||
|
{
|
||||||
|
// System.out.println( "remove:" + node.key + ":" + System.identityHashCode(node.key));
|
||||||
|
// m_nodeTree.delete( node.getKey() );
|
||||||
|
aFront.removeNode( node );
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdvancingFrontNode locateNode( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
return aFront.locateNode( point );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createAdvancingFront()
|
||||||
|
{
|
||||||
|
AdvancingFrontNode head,tail,middle;
|
||||||
|
// Initial triangle
|
||||||
|
DelaunayTriangle iTriangle = new DelaunayTriangle( _points.get(0),
|
||||||
|
getTail(),
|
||||||
|
getHead() );
|
||||||
|
addToList( iTriangle );
|
||||||
|
|
||||||
|
head = new AdvancingFrontNode( iTriangle.points[1] );
|
||||||
|
head.triangle = iTriangle;
|
||||||
|
middle = new AdvancingFrontNode( iTriangle.points[0] );
|
||||||
|
middle.triangle = iTriangle;
|
||||||
|
tail = new AdvancingFrontNode( iTriangle.points[2] );
|
||||||
|
|
||||||
|
aFront = new AdvancingFront( head, tail );
|
||||||
|
aFront.addNode( middle );
|
||||||
|
|
||||||
|
// TODO: I think it would be more intuitive if head is middles next and not previous
|
||||||
|
// so swap head and tail
|
||||||
|
aFront.head.next = middle;
|
||||||
|
middle.next = aFront.tail;
|
||||||
|
middle.prev = aFront.head;
|
||||||
|
aFront.tail.prev = middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Basin
|
||||||
|
{
|
||||||
|
AdvancingFrontNode leftNode;
|
||||||
|
AdvancingFrontNode bottomNode;
|
||||||
|
AdvancingFrontNode rightNode;
|
||||||
|
public double width;
|
||||||
|
public boolean leftHighest;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EdgeEvent
|
||||||
|
{
|
||||||
|
DTSweepConstraint constrainedEdge;
|
||||||
|
public boolean right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to map a node to all sides of this triangle that don't have
|
||||||
|
* a neighbor.
|
||||||
|
*
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
public void mapTriangleToNodes( DelaunayTriangle t )
|
||||||
|
{
|
||||||
|
AdvancingFrontNode n;
|
||||||
|
for( int i=0; i<3; i++ )
|
||||||
|
{
|
||||||
|
if( t.neighbors[i] == null )
|
||||||
|
{
|
||||||
|
n = aFront.locatePoint( t.pointCW( t.points[i] ) );
|
||||||
|
if( n != null )
|
||||||
|
{
|
||||||
|
n.triangle = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareTriangulation( Triangulatable t )
|
||||||
|
{
|
||||||
|
super.prepareTriangulation( t );
|
||||||
|
|
||||||
|
double xmax, xmin;
|
||||||
|
double ymax, ymin;
|
||||||
|
|
||||||
|
xmax = xmin = _points.get(0).getX();
|
||||||
|
ymax = ymin = _points.get(0).getY();
|
||||||
|
// Calculate bounds. Should be combined with the sorting
|
||||||
|
for( TriangulationPoint p : _points )
|
||||||
|
{
|
||||||
|
if( p.getX() > xmax )
|
||||||
|
xmax = p.getX();
|
||||||
|
if( p.getX() < xmin )
|
||||||
|
xmin = p.getX();
|
||||||
|
if( p.getY() > ymax )
|
||||||
|
ymax = p.getY();
|
||||||
|
if( p.getY() < ymin )
|
||||||
|
ymin = p.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
double deltaX = ALPHA * ( xmax - xmin );
|
||||||
|
double deltaY = ALPHA * ( ymax - ymin );
|
||||||
|
TPoint p1 = new TPoint( xmax + deltaX, ymin - deltaY );
|
||||||
|
TPoint p2 = new TPoint( xmin - deltaX, ymin - deltaY );
|
||||||
|
|
||||||
|
setHead( p1 );
|
||||||
|
setTail( p2 );
|
||||||
|
|
||||||
|
// long time = System.nanoTime();
|
||||||
|
// Sort the points along y-axis
|
||||||
|
Collections.sort( _points, _comparator );
|
||||||
|
// logger.info( "Triangulation setup [{}ms]", ( System.nanoTime() - time ) / 1e6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void finalizeTriangulation()
|
||||||
|
{
|
||||||
|
_triUnit.addTriangles( _triList );
|
||||||
|
_triList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TriangulationConstraint newConstraint( TriangulationPoint a, TriangulationPoint b )
|
||||||
|
{
|
||||||
|
return new DTSweepConstraint( a, b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TriangulationAlgorithm algorithm()
|
||||||
|
{
|
||||||
|
return TriangulationAlgorithm.DTSweep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationDebugContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
public class DTSweepDebugContext extends TriangulationDebugContext
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Fields used for visual representation of current triangulation
|
||||||
|
*/
|
||||||
|
protected DelaunayTriangle _primaryTriangle;
|
||||||
|
protected DelaunayTriangle _secondaryTriangle;
|
||||||
|
protected TriangulationPoint _activePoint;
|
||||||
|
protected AdvancingFrontNode _activeNode;
|
||||||
|
protected DTSweepConstraint _activeConstraint;
|
||||||
|
|
||||||
|
public DTSweepDebugContext( DTSweepContext tcx )
|
||||||
|
{
|
||||||
|
super( tcx );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebugContext()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private Tuple2<TPoint,Double> m_circumCircle = new Tuple2<TPoint,Double>( new TPoint(), new Double(0) );
|
||||||
|
// public Tuple2<TPoint,Double> getCircumCircle() { return m_circumCircle; }
|
||||||
|
public DelaunayTriangle getPrimaryTriangle()
|
||||||
|
{
|
||||||
|
return _primaryTriangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelaunayTriangle getSecondaryTriangle()
|
||||||
|
{
|
||||||
|
return _secondaryTriangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdvancingFrontNode getActiveNode()
|
||||||
|
{
|
||||||
|
return _activeNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DTSweepConstraint getActiveConstraint()
|
||||||
|
{
|
||||||
|
return _activeConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationPoint getActivePoint()
|
||||||
|
{
|
||||||
|
return _activePoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrimaryTriangle( DelaunayTriangle triangle )
|
||||||
|
{
|
||||||
|
_primaryTriangle = triangle;
|
||||||
|
_tcx.update("setPrimaryTriangle");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecondaryTriangle( DelaunayTriangle triangle )
|
||||||
|
{
|
||||||
|
_secondaryTriangle = triangle;
|
||||||
|
_tcx.update("setSecondaryTriangle");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActivePoint( TriangulationPoint point )
|
||||||
|
{
|
||||||
|
_activePoint = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActiveConstraint( DTSweepConstraint e )
|
||||||
|
{
|
||||||
|
_activeConstraint = e;
|
||||||
|
_tcx.update("setWorkingSegment");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActiveNode( AdvancingFrontNode node )
|
||||||
|
{
|
||||||
|
_activeNode = node;
|
||||||
|
_tcx.update("setWorkingNode");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
_primaryTriangle = null;
|
||||||
|
_secondaryTriangle = null;
|
||||||
|
_activePoint = null;
|
||||||
|
_activeNode = null;
|
||||||
|
_activeConstraint = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void setWorkingCircumCircle( TPoint point, TPoint point2, TPoint point3 )
|
||||||
|
// {
|
||||||
|
// double dx,dy;
|
||||||
|
//
|
||||||
|
// CircleXY.circumCenter( point, point2, point3, m_circumCircle.a );
|
||||||
|
// dx = m_circumCircle.a.getX()-point.getX();
|
||||||
|
// dy = m_circumCircle.a.getY()-point.getY();
|
||||||
|
// m_circumCircle.b = Double.valueOf( Math.sqrt( dx*dx + dy*dy ) );
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
|
||||||
|
public class DTSweepPointComparator implements Comparator<TriangulationPoint>
|
||||||
|
{
|
||||||
|
public int compare( TriangulationPoint p1, TriangulationPoint p2 )
|
||||||
|
{
|
||||||
|
if(p1.getY() < p2.getY() )
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if( p1.getY() > p2.getY())
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(p1.getX() < p2.getX())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if( p1.getX() > p2.getX() )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.poly2tri.triangulation.delaunay.sweep;
|
||||||
|
|
||||||
|
public class PointOnEdgeException extends RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public PointOnEdgeException( String msg )
|
||||||
|
{
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/org/poly2tri/triangulation/point/FloatBufferPoint.java
Normal file
94
src/org/poly2tri/triangulation/point/FloatBufferPoint.java
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.point;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
|
||||||
|
|
||||||
|
public class FloatBufferPoint extends TriangulationPoint
|
||||||
|
{
|
||||||
|
private final FloatBuffer _fb;
|
||||||
|
private final int _ix,_iy,_iz;
|
||||||
|
|
||||||
|
public FloatBufferPoint( FloatBuffer fb, int index )
|
||||||
|
{
|
||||||
|
_fb = fb;
|
||||||
|
_ix = index;
|
||||||
|
_iy = index+1;
|
||||||
|
_iz = index+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final double getX()
|
||||||
|
{
|
||||||
|
return _fb.get( _ix );
|
||||||
|
}
|
||||||
|
public final double getY()
|
||||||
|
{
|
||||||
|
return _fb.get( _iy );
|
||||||
|
}
|
||||||
|
public final double getZ()
|
||||||
|
{
|
||||||
|
return _fb.get( _iz );
|
||||||
|
}
|
||||||
|
|
||||||
|
public final float getXf()
|
||||||
|
{
|
||||||
|
return _fb.get( _ix );
|
||||||
|
}
|
||||||
|
public final float getYf()
|
||||||
|
{
|
||||||
|
return _fb.get( _iy );
|
||||||
|
}
|
||||||
|
public final float getZf()
|
||||||
|
{
|
||||||
|
return _fb.get( _iz );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set( double x, double y, double z )
|
||||||
|
{
|
||||||
|
_fb.put( _ix, (float)x );
|
||||||
|
_fb.put( _iy, (float)y );
|
||||||
|
_fb.put( _iz, (float)z );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TriangulationPoint[] toPoints( FloatBuffer fb )
|
||||||
|
{
|
||||||
|
FloatBufferPoint[] points = new FloatBufferPoint[fb.limit()/3];
|
||||||
|
for( int i=0,j=0; i<points.length; i++, j+=3 )
|
||||||
|
{
|
||||||
|
points[i] = new FloatBufferPoint(fb, j);
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/org/poly2tri/triangulation/point/TPoint.java
Normal file
69
src/org/poly2tri/triangulation/point/TPoint.java
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.point;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
|
||||||
|
public class TPoint extends TriangulationPoint
|
||||||
|
{
|
||||||
|
private double _x;
|
||||||
|
private double _y;
|
||||||
|
private double _z;
|
||||||
|
|
||||||
|
public TPoint( double x, double y )
|
||||||
|
{
|
||||||
|
this( x, y, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TPoint( double x, double y, double z )
|
||||||
|
{
|
||||||
|
_x = x;
|
||||||
|
_y = y;
|
||||||
|
_z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() { return _x; }
|
||||||
|
public double getY() { return _y; }
|
||||||
|
public double getZ() { return _z; }
|
||||||
|
|
||||||
|
public float getXf() { return (float)_x; }
|
||||||
|
public float getYf() { return (float)_y; }
|
||||||
|
public float getZf() { return (float)_z; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set( double x, double y, double z )
|
||||||
|
{
|
||||||
|
_x = x;
|
||||||
|
_y = y;
|
||||||
|
_z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
121
src/org/poly2tri/triangulation/sets/ConstrainedPointSet.java
Normal file
121
src/org/poly2tri/triangulation/sets/ConstrainedPointSet.java
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.sets;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationMode;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the PointSet by adding some Constraints on how it will be triangulated<br>
|
||||||
|
* A constraint defines an edge between two points in the set, these edges can not
|
||||||
|
* be crossed. They will be enforced triangle edges after a triangulation.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Thomas Åhlén, thahlen@gmail.com
|
||||||
|
*/
|
||||||
|
public class ConstrainedPointSet extends PointSet
|
||||||
|
{
|
||||||
|
int[] _index;
|
||||||
|
List<TriangulationPoint> _constrainedPointList = null;
|
||||||
|
|
||||||
|
public ConstrainedPointSet( List<TriangulationPoint> points, int[] index )
|
||||||
|
{
|
||||||
|
super( points );
|
||||||
|
_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param points - A list of all points in PointSet
|
||||||
|
* @param constraints - Pairs of two points defining a constraint, all points <b>must</b> be part of given PointSet!
|
||||||
|
*/
|
||||||
|
public ConstrainedPointSet( List<TriangulationPoint> points, List<TriangulationPoint> constraints )
|
||||||
|
{
|
||||||
|
super( points );
|
||||||
|
_constrainedPointList = new ArrayList<TriangulationPoint>();
|
||||||
|
_constrainedPointList.addAll(constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TriangulationMode getTriangulationMode()
|
||||||
|
{
|
||||||
|
return TriangulationMode.CONSTRAINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getEdgeIndex()
|
||||||
|
{
|
||||||
|
return _index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void prepareTriangulation( TriangulationContext tcx )
|
||||||
|
{
|
||||||
|
super.prepareTriangulation( tcx );
|
||||||
|
if( _constrainedPointList != null )
|
||||||
|
{
|
||||||
|
TriangulationPoint p1,p2;
|
||||||
|
Iterator iterator = _constrainedPointList.iterator();
|
||||||
|
while(iterator.hasNext())
|
||||||
|
{
|
||||||
|
p1 = (TriangulationPoint)iterator.next();
|
||||||
|
p2 = (TriangulationPoint)iterator.next();
|
||||||
|
tcx.newConstraint(p1,p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( int i = 0; i < _index.length; i+=2 )
|
||||||
|
{
|
||||||
|
// XXX: must change!!
|
||||||
|
tcx.newConstraint( _points.get( _index[i] ), _points.get( _index[i+1] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: TO BE IMPLEMENTED!
|
||||||
|
* Peforms a validation on given input<br>
|
||||||
|
* 1. Check's if there any constraint edges are crossing or collinear<br>
|
||||||
|
* 2.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/org/poly2tri/triangulation/sets/PointSet.java
Normal file
95
src/org/poly2tri/triangulation/sets/PointSet.java
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.sets;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.Triangulatable;
|
||||||
|
import org.poly2tri.triangulation.TriangulationContext;
|
||||||
|
import org.poly2tri.triangulation.TriangulationMode;
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||||
|
|
||||||
|
public class PointSet implements Triangulatable
|
||||||
|
{
|
||||||
|
List<TriangulationPoint> _points;
|
||||||
|
List<DelaunayTriangle> _triangles;
|
||||||
|
|
||||||
|
public PointSet( List<TriangulationPoint> points )
|
||||||
|
{
|
||||||
|
_points = new ArrayList<TriangulationPoint>();
|
||||||
|
_points.addAll( points );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriangulationMode getTriangulationMode()
|
||||||
|
{
|
||||||
|
return TriangulationMode.UNCONSTRAINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TriangulationPoint> getPoints()
|
||||||
|
{
|
||||||
|
return _points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DelaunayTriangle> getTriangles()
|
||||||
|
{
|
||||||
|
return _triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTriangle( DelaunayTriangle t )
|
||||||
|
{
|
||||||
|
_triangles.add( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTriangles( List<DelaunayTriangle> list )
|
||||||
|
{
|
||||||
|
_triangles.addAll( list );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearTriangulation()
|
||||||
|
{
|
||||||
|
_triangles.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepareTriangulation( TriangulationContext<?> tcx )
|
||||||
|
{
|
||||||
|
if( _triangles == null )
|
||||||
|
{
|
||||||
|
_triangles = new ArrayList<DelaunayTriangle>( _points.size() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_triangles.clear();
|
||||||
|
}
|
||||||
|
tcx.addPoints( _points );
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/org/poly2tri/triangulation/util/PointGenerator.java
Normal file
38
src/org/poly2tri/triangulation/util/PointGenerator.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package org.poly2tri.triangulation.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.poly2tri.triangulation.TriangulationPoint;
|
||||||
|
import org.poly2tri.triangulation.point.TPoint;
|
||||||
|
|
||||||
|
public class PointGenerator
|
||||||
|
{
|
||||||
|
public static List<TriangulationPoint> uniformDistribution( int n, double scale )
|
||||||
|
{
|
||||||
|
ArrayList<TriangulationPoint> points = new ArrayList<TriangulationPoint>();
|
||||||
|
for( int i=0; i<n; i++ )
|
||||||
|
{
|
||||||
|
points.add( new TPoint( scale*(0.5 - Math.random()), scale*(0.5 - Math.random()) ) );
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TriangulationPoint> uniformGrid( int n, double scale )
|
||||||
|
{
|
||||||
|
double x=0;
|
||||||
|
double size = scale/n;
|
||||||
|
double halfScale = 0.5*scale;
|
||||||
|
|
||||||
|
ArrayList<TriangulationPoint> points = new ArrayList<TriangulationPoint>();
|
||||||
|
for( int i=0; i<n+1; i++ )
|
||||||
|
{
|
||||||
|
x = halfScale - i*size;
|
||||||
|
for( int j=0; j<n+1; j++ )
|
||||||
|
{
|
||||||
|
points.add( new TPoint( x, halfScale - j*size ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/org/poly2tri/triangulation/util/PolygonGenerator.java
Normal file
94
src/org/poly2tri/triangulation/util/PolygonGenerator.java
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.util;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.polygon.Polygon;
|
||||||
|
import org.poly2tri.geometry.polygon.PolygonPoint;
|
||||||
|
|
||||||
|
public class PolygonGenerator
|
||||||
|
{
|
||||||
|
private static final double PI_2 = 2.0*Math.PI;
|
||||||
|
|
||||||
|
public static Polygon RandomCircleSweep( double scale, int vertexCount )
|
||||||
|
{
|
||||||
|
PolygonPoint point;
|
||||||
|
PolygonPoint[] points;
|
||||||
|
double radius = scale/4;
|
||||||
|
|
||||||
|
points = new PolygonPoint[vertexCount];
|
||||||
|
for(int i=0; i<vertexCount; i++)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if( i%250 == 0 )
|
||||||
|
{
|
||||||
|
radius += scale/2*(0.5 - Math.random());
|
||||||
|
}
|
||||||
|
else if( i%50 == 0 )
|
||||||
|
{
|
||||||
|
radius += scale/5*(0.5 - Math.random());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
radius += 25*scale/vertexCount*(0.5 - Math.random());
|
||||||
|
}
|
||||||
|
radius = radius > scale/2 ? scale/2 : radius;
|
||||||
|
radius = radius < scale/10 ? scale/10 : radius;
|
||||||
|
} while( radius < scale/10 || radius > scale/2 );
|
||||||
|
point = new PolygonPoint( radius*Math.cos( (PI_2*i)/vertexCount ),
|
||||||
|
radius*Math.sin( (PI_2*i)/vertexCount ) );
|
||||||
|
points[i] = point;
|
||||||
|
}
|
||||||
|
return new Polygon( points );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Polygon RandomCircleSweep2( double scale, int vertexCount )
|
||||||
|
{
|
||||||
|
PolygonPoint point;
|
||||||
|
PolygonPoint[] points;
|
||||||
|
double radius = scale/4;
|
||||||
|
|
||||||
|
points = new PolygonPoint[vertexCount];
|
||||||
|
for(int i=0; i<vertexCount; i++)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
radius += scale/5*(0.5 - Math.random());
|
||||||
|
radius = radius > scale/2 ? scale/2 : radius;
|
||||||
|
radius = radius < scale/10 ? scale/10 : radius;
|
||||||
|
} while( radius < scale/10 || radius > scale/2 );
|
||||||
|
point = new PolygonPoint( radius*Math.cos( (PI_2*i)/vertexCount ),
|
||||||
|
radius*Math.sin( (PI_2*i)/vertexCount ) );
|
||||||
|
points[i] = point;
|
||||||
|
}
|
||||||
|
return new Polygon( points );
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/org/poly2tri/triangulation/util/QuadTreeRefinement.java
Normal file
17
src/org/poly2tri/triangulation/util/QuadTreeRefinement.java
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
package org.poly2tri.triangulation.util;
|
||||||
|
|
||||||
|
import org.poly2tri.geometry.polygon.Polygon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a QuadTree traversal to add steiner points
|
||||||
|
* inside the polygon that needs refinement
|
||||||
|
*
|
||||||
|
* @author thahlen@gmail.com
|
||||||
|
*/
|
||||||
|
public class QuadTreeRefinement
|
||||||
|
{
|
||||||
|
public static final void refine( Polygon p, int depth )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/org/poly2tri/triangulation/util/Tuple2.java
Normal file
43
src/org/poly2tri/triangulation/util/Tuple2.java
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.util;
|
||||||
|
|
||||||
|
public class Tuple2<A,B>
|
||||||
|
{
|
||||||
|
public A a;
|
||||||
|
public B b;
|
||||||
|
|
||||||
|
public Tuple2(A a,B b)
|
||||||
|
{
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/org/poly2tri/triangulation/util/Tuple3.java
Normal file
45
src/org/poly2tri/triangulation/util/Tuple3.java
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* Poly2Tri
|
||||||
|
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||||
|
* http://code.google.com/p/poly2tri/
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.poly2tri.triangulation.util;
|
||||||
|
|
||||||
|
public class Tuple3<A,B,C>
|
||||||
|
{
|
||||||
|
public A a;
|
||||||
|
public B b;
|
||||||
|
public C c;
|
||||||
|
|
||||||
|
public Tuple3(A a,B b,C c)
|
||||||
|
{
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue