mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-23 17:04:00 +01:00
getting pick ray
This commit is contained in:
parent
8aa85d9219
commit
2c42974329
17 changed files with 1684 additions and 388 deletions
324
src/cad/Cad.java
324
src/cad/Cad.java
|
|
@ -1,77 +1,34 @@
|
|||
package cad;
|
||||
|
||||
import cad.fx.Plane;
|
||||
import cad.fx.Utils3D;
|
||||
import cad.math.Vector;
|
||||
import cad.gl.MeshNode;
|
||||
import cad.gl.Scene;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
import com.jogamp.opengl.util.gl2.GLUT;
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
|
||||
import javax.media.opengl.GL;
|
||||
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.Threading;
|
||||
import javax.media.opengl.glu.GLU;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
public class Cad implements GLEventListener, com.jogamp.newt.event.MouseListener {
|
||||
|
||||
public class Cad {
|
||||
|
||||
static {
|
||||
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||
}
|
||||
|
||||
public static List<Plane> initObjects = Utils3D.createCube(1);
|
||||
|
||||
static TIntObjectMap<Plane> scene = new TIntObjectHashMap<>();
|
||||
|
||||
private static GLWindow window;
|
||||
|
||||
ExecutorService updater = Executors.newSingleThreadExecutor();
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
|
||||
|
||||
|
||||
// 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
|
||||
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
|
||||
// }
|
||||
// }.start();
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
window.addGLEventListener(new Cad());
|
||||
GLWindow window = GLWindow.create(caps);
|
||||
|
||||
Scene scene = new Scene(window);
|
||||
scene.addNode(new MeshNode(Utils3D.createCube(1)));
|
||||
window.setSize(640, 480);
|
||||
window.setTitle("CAD");
|
||||
window.setVisible(true);
|
||||
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
Object monitor = new Object();
|
||||
while (true) {
|
||||
|
|
@ -83,272 +40,5 @@ public class Cad implements GLEventListener, com.jogamp.newt.event.MouseListener
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
// animator.start();
|
||||
}
|
||||
|
||||
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};
|
||||
float white[] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
|
||||
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 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(0);
|
||||
|
||||
float pos0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos0, 0);
|
||||
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
|
||||
initNodes(gl);
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
if (drawable instanceof GLWindow) {
|
||||
GLWindow awtDrawable = (GLWindow) drawable;
|
||||
awtDrawable.addMouseListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void initNodes(GL2 gl) {
|
||||
for (Plane plane : initObjects) {
|
||||
int id = gl.glGenLists(1);
|
||||
scene.put(id, plane);
|
||||
gl.glNewList(id, GL2.GL_COMPILE);
|
||||
|
||||
//http://devernay.free.fr/cours/opengl/materials.html
|
||||
// float[] amb = {0f, 0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, amb, 0);
|
||||
|
||||
float[] diff = {0.6901961f, 0.76862746f, 0.87058824f};
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, diff, 0);
|
||||
|
||||
// float[] spec = {0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, spec, 0);
|
||||
// float shine = 0.6f;
|
||||
// gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shine * 128.0f);
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
gl.glNormal3d(plane.normal.x, plane.normal.y, plane.normal.z); //very important!!
|
||||
for (Vector[] tr : plane.getTriangles()) {
|
||||
gl.glVertex3d(tr[0].x, tr[0].y, tr[0].z);
|
||||
gl.glVertex3d(tr[1].x, tr[1].y, tr[1].z);
|
||||
gl.glVertex3d(tr[2].x, tr[2].y, tr[2].z);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
gl.glEndList();
|
||||
}
|
||||
for (Plane plane : initObjects) {
|
||||
int id = gl.glGenLists(1);
|
||||
scene.put(id, plane);
|
||||
gl.glNewList(id, GL2.GL_COMPILE);
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glNormal3d(plane.normal.x, plane.normal.y, plane.normal.z);
|
||||
for (int i = 0; i < plane.shell.size(); i++) {
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
Vector a = Plane.get(plane.shell, i);
|
||||
Vector b = Plane.get(plane.shell, i + 1);
|
||||
gl.glVertex3d(a.x, a.y, a.z);
|
||||
gl.glVertex3d(b.x, b.y, b.z);
|
||||
gl.glEnd();
|
||||
}
|
||||
gl.glEndList();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
gl.glClearColor(0.5019608f, 0.5019608f, 0.5019608f, 0f);
|
||||
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.glPushMatrix();
|
||||
gl.glScalef(scale, scale, scale);
|
||||
|
||||
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);
|
||||
|
||||
for (int id : scene.keys()) {
|
||||
gl.glCallList(id);
|
||||
}
|
||||
|
||||
//
|
||||
// gl.glPushMatrix();
|
||||
// gl.glScalef(3,3,3);
|
||||
// gl.glBegin(GL2.GL_QUADS);
|
||||
// gl.glNormal3f( 0.0F, 0.0F, 1.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f(-0.5F, 0.5F, 0.5F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F, 0.5F); gl.glVertex3f( 0.5F,-0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F, 0.0F,-1.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f(-0.5F, 0.5F,-0.5F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F,-0.5F); gl.glVertex3f( 0.5F,-0.5F,-0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F, 1.0F, 0.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f( 0.5F, 0.5F,-0.5F);
|
||||
// gl.glVertex3f(-0.5F, 0.5F,-0.5F); gl.glVertex3f(-0.5F, 0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F,-1.0F, 0.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f( 0.5F,-0.5F,-0.5F);
|
||||
// gl.glVertex3f( 0.5F,-0.5F, 0.5F); gl.glVertex3f(-0.5F,-0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 1.0F, 0.0F, 0.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f( 0.5F,-0.5F, 0.5F);
|
||||
// gl.glVertex3f( 0.5F,-0.5F,-0.5F); gl.glVertex3f( 0.5F, 0.5F,-0.5F);
|
||||
//
|
||||
// gl.glNormal3f(-1.0F, 0.0F, 0.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f(-0.5F,-0.5F, 0.5F);
|
||||
// gl.glVertex3f(-0.5F, 0.5F, 0.5F); gl.glVertex3f(-0.5F, 0.5F,-0.5F);
|
||||
// gl.glEnd();
|
||||
// gl.glPopMatrix();
|
||||
|
||||
|
||||
gl.glPopMatrix();
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
int width = window.getWidth();
|
||||
int height = window.getHeight();
|
||||
|
||||
float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) width);
|
||||
float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
|
||||
|
||||
volatile boolean updating = false;
|
||||
|
||||
private void update(Runnable op) {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
Threading.invokeOnOpenGLThread(false, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
updating = true;
|
||||
|
||||
op.run();
|
||||
} finally {
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// updater.execute(() -> {
|
||||
// try {
|
||||
// updating = true;
|
||||
//
|
||||
// op.run();
|
||||
// } finally {
|
||||
// updating = false;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
float scale = 1;
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
|
||||
double scaleFactor = e.getRotation()[1] > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||
scale *= scaleFactor;
|
||||
update(window::display);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
349
src/cad/Cad3.java
Normal file
349
src/cad/Cad3.java
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
package cad;
|
||||
|
||||
import cad.fx.Polygon;
|
||||
import cad.fx.Utils3D;
|
||||
import cad.math.Vector;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
|
||||
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.Threading;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Cad3 implements GLEventListener, com.jogamp.newt.event.MouseListener {
|
||||
|
||||
|
||||
static {
|
||||
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||
}
|
||||
|
||||
public static List<Polygon> initObjects = Utils3D.createCube(1);
|
||||
|
||||
static TIntObjectMap<Polygon> scene = new TIntObjectHashMap<>();
|
||||
|
||||
private static GLWindow window;
|
||||
|
||||
ExecutorService updater = Executors.newSingleThreadExecutor();
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
|
||||
|
||||
|
||||
// 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
|
||||
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
|
||||
// }
|
||||
// }.start();
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
window.addGLEventListener(new Cad3());
|
||||
|
||||
window.setSize(640, 480);
|
||||
window.setTitle("CAD");
|
||||
window.setVisible(true);
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
Object monitor = new Object();
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (monitor) {
|
||||
monitor.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// animator.start();
|
||||
}
|
||||
|
||||
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};
|
||||
float white[] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
|
||||
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 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(0);
|
||||
|
||||
float pos0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos0, 0);
|
||||
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
|
||||
initNodes(gl);
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
if (drawable instanceof GLWindow) {
|
||||
GLWindow awtDrawable = (GLWindow) drawable;
|
||||
awtDrawable.addMouseListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void initNodes(GL2 gl) {
|
||||
for (Polygon poly : initObjects) {
|
||||
int id = gl.glGenLists(1);
|
||||
scene.put(id, poly);
|
||||
gl.glNewList(id, GL2.GL_COMPILE);
|
||||
|
||||
//http://devernay.free.fr/cours/opengl/materials.html
|
||||
// float[] amb = {0f, 0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, amb, 0);
|
||||
|
||||
float[] diff = {0.6901961f, 0.76862746f, 0.87058824f};
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, diff, 0);
|
||||
|
||||
// float[] spec = {0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, spec, 0);
|
||||
// float shine = 0.6f;
|
||||
// gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shine * 128.0f);
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
gl.glNormal3d(poly.normal.x, poly.normal.y, poly.normal.z); //very important!!
|
||||
for (Vector[] tr : poly.getTriangles()) {
|
||||
gl.glVertex3d(tr[0].x, tr[0].y, tr[0].z);
|
||||
gl.glVertex3d(tr[1].x, tr[1].y, tr[1].z);
|
||||
gl.glVertex3d(tr[2].x, tr[2].y, tr[2].z);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
gl.glEndList();
|
||||
}
|
||||
for (Polygon poly : initObjects) {
|
||||
int id = gl.glGenLists(1);
|
||||
scene.put(id, poly);
|
||||
gl.glNewList(id, GL2.GL_COMPILE);
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glNormal3d(poly.normal.x, poly.normal.y, poly.normal.z);
|
||||
for (int i = 0; i < poly.shell.size(); i++) {
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
Vector a = Polygon.get(poly.shell, i);
|
||||
Vector b = Polygon.get(poly.shell, i + 1);
|
||||
gl.glVertex3d(a.x, a.y, a.z);
|
||||
gl.glVertex3d(b.x, b.y, b.z);
|
||||
gl.glEnd();
|
||||
}
|
||||
gl.glEndList();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
gl.glClearColor(0.5019608f, 0.5019608f, 0.5019608f, 0f);
|
||||
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.glPushMatrix();
|
||||
gl.glScalef(scale, scale, scale);
|
||||
|
||||
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);
|
||||
|
||||
for (int id : scene.keys()) {
|
||||
gl.glCallList(id);
|
||||
}
|
||||
|
||||
//
|
||||
// gl.glPushMatrix();
|
||||
// gl.glScalef(3,3,3);
|
||||
// gl.glBegin(GL2.GL_QUADS);
|
||||
// gl.glNormal3f( 0.0F, 0.0F, 1.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f(-0.5F, 0.5F, 0.5F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F, 0.5F); gl.glVertex3f( 0.5F,-0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F, 0.0F,-1.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f(-0.5F, 0.5F,-0.5F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F,-0.5F); gl.glVertex3f( 0.5F,-0.5F,-0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F, 1.0F, 0.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f( 0.5F, 0.5F,-0.5F);
|
||||
// gl.glVertex3f(-0.5F, 0.5F,-0.5F); gl.glVertex3f(-0.5F, 0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F,-1.0F, 0.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f( 0.5F,-0.5F,-0.5F);
|
||||
// gl.glVertex3f( 0.5F,-0.5F, 0.5F); gl.glVertex3f(-0.5F,-0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 1.0F, 0.0F, 0.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f( 0.5F,-0.5F, 0.5F);
|
||||
// gl.glVertex3f( 0.5F,-0.5F,-0.5F); gl.glVertex3f( 0.5F, 0.5F,-0.5F);
|
||||
//
|
||||
// gl.glNormal3f(-1.0F, 0.0F, 0.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f(-0.5F,-0.5F, 0.5F);
|
||||
// gl.glVertex3f(-0.5F, 0.5F, 0.5F); gl.glVertex3f(-0.5F, 0.5F,-0.5F);
|
||||
// gl.glEnd();
|
||||
// gl.glPopMatrix();
|
||||
|
||||
|
||||
gl.glPopMatrix();
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
int width = window.getWidth();
|
||||
int height = window.getHeight();
|
||||
|
||||
float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) width);
|
||||
float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
|
||||
|
||||
volatile boolean updating = false;
|
||||
|
||||
private void update(Runnable op) {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
Threading.invokeOnOpenGLThread(false, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
updating = true;
|
||||
|
||||
op.run();
|
||||
} finally {
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// updater.execute(() -> {
|
||||
// try {
|
||||
// updating = true;
|
||||
//
|
||||
// op.run();
|
||||
// } finally {
|
||||
// updating = false;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
float scale = 1;
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
|
||||
double scaleFactor = e.getRotation()[1] > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||
scale *= scaleFactor;
|
||||
update(window::display);
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ public class AppCtrl implements Initializable {
|
|||
}
|
||||
|
||||
private void setInitObject(Group parent) {
|
||||
List<Plane> cube = Utils3D.createCube(100);
|
||||
List<Polygon> cube = Utils3D.createCube(100);
|
||||
parent.getChildren().addAll(cadContext.toNodes(cube));
|
||||
//
|
||||
// CSG init = new Cube(100).toCSG().difference(new Cylinder(30, 100, 10).toCSG());
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ import javafx.scene.shape.TriangleMesh;
|
|||
|
||||
public class CSGMesh extends TriangleMesh {
|
||||
|
||||
public final TIntObjectMap<Plane> polygons = new TIntObjectHashMap<>();
|
||||
public final TIntObjectMap<Polygon> polygons = new TIntObjectHashMap<>();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package cad.fx;
|
||||
|
||||
import eu.mihosoft.vrl.v3d.Polygon;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.shape.MeshView;
|
||||
|
||||
|
|
@ -26,22 +25,22 @@ public class CSGNode extends MeshView {
|
|||
});
|
||||
}
|
||||
|
||||
private void highlight(Polygon poly) {
|
||||
private void highlight(eu.mihosoft.vrl.v3d.Polygon poly) {
|
||||
System.out.println(poly);
|
||||
}
|
||||
|
||||
private void select(Polygon poly) {
|
||||
private void select(eu.mihosoft.vrl.v3d.Polygon poly) {
|
||||
System.out.println(poly);
|
||||
}
|
||||
|
||||
public final Map<Plane, Sketch> sketches = new HashMap<>();
|
||||
public final Map<Polygon, Sketch> sketches = new HashMap<>();
|
||||
|
||||
public Sketch getSketch(Plane plane) {
|
||||
Sketch sketch = sketches.get(plane);
|
||||
public Sketch getSketch(Polygon poly) {
|
||||
Sketch sketch = sketches.get(poly);
|
||||
if (sketch == null) {
|
||||
sketch = new Sketch(plane);
|
||||
sketch = new Sketch(poly);
|
||||
((Group) getParent()).getChildren().add(sketch.drawLayer);
|
||||
sketches.put(plane, sketch);
|
||||
sketches.put(poly, sketch);
|
||||
}
|
||||
return sketch;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,20 +72,20 @@ public class CadContext {
|
|||
PickResult pickResult = e.getPickResult();
|
||||
int face = pickResult.getIntersectedFace();
|
||||
CSGMesh csgMesh = (CSGMesh) csgNode.getMesh();
|
||||
Plane plane = csgMesh.polygons.get(face);
|
||||
System.out.println(plane);
|
||||
if (plane != null) {
|
||||
Polygon poly = csgMesh.polygons.get(face);
|
||||
System.out.println(poly);
|
||||
if (poly != null) {
|
||||
if (selection != null) {
|
||||
boolean isSameNode = selection.sameTo(csgNode, plane);
|
||||
boolean isSameNode = selection.sameTo(csgNode, poly);
|
||||
if (sketcher == null && !isSameNode) {
|
||||
selection = new Selection(csgNode, plane);
|
||||
selection = new Selection(csgNode, poly);
|
||||
}
|
||||
if (sketcher != null && isSameNode) {
|
||||
sketcher.addPoint(pickResult.getIntersectedPoint());
|
||||
}
|
||||
} else {
|
||||
if (sketcher == null) {
|
||||
selection = new Selection(csgNode, plane);
|
||||
selection = new Selection(csgNode, poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +95,7 @@ public class CadContext {
|
|||
if (sketcher != null || selection == null) {
|
||||
return;
|
||||
}
|
||||
sketcher = new Sketcher(selection.csgNode.getSketch(selection.plane));
|
||||
sketcher = new Sketcher(selection.csgNode.getSketch(selection.poly));
|
||||
}
|
||||
|
||||
public void endSketching() {
|
||||
|
|
@ -111,43 +111,43 @@ public class CadContext {
|
|||
return;
|
||||
}
|
||||
|
||||
Sketch sketch = selection.csgNode.getSketch(selection.plane);
|
||||
Sketch sketch = selection.csgNode.getSketch(selection.poly);
|
||||
Vector dir = sketch.owner.normal.scale(height);
|
||||
for (List<Vector> polygon : sketch.polygons) {
|
||||
if (polygon.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Plane plane = new Plane(sketch.owner.normal, polygon, Collections.emptyList());
|
||||
List<Plane> extruded = Plane.extrude(plane, dir);
|
||||
Polygon poly = new Polygon(sketch.owner.normal, polygon, Collections.emptyList());
|
||||
List<Polygon> extruded = Polygon.extrude(poly, dir);
|
||||
|
||||
for (Plane s : extruded) {
|
||||
for (Polygon s : extruded) {
|
||||
sketch.drawLayer.getChildren().addAll(toNodes(extruded));// fixme
|
||||
}
|
||||
// CSG pad = Extrude.points(dir, polygon);
|
||||
}
|
||||
}
|
||||
|
||||
public List<CSGNode> toNodes(List<Plane> extruded) {
|
||||
public List<CSGNode> toNodes(List<Polygon> extruded) {
|
||||
return extruded.stream().map(this::toNode).collect(toList());
|
||||
}
|
||||
|
||||
public CSGNode toNode(Plane plane) {
|
||||
return new CSGNode(Utils3D.getMesh(Collections.singletonList(plane)), this);
|
||||
public CSGNode toNode(Polygon poly) {
|
||||
return new CSGNode(Utils3D.getMesh(Collections.singletonList(poly)), this);
|
||||
}
|
||||
|
||||
public static class Selection {
|
||||
|
||||
public final CSGNode csgNode;
|
||||
public final Plane plane;
|
||||
public final Polygon poly;
|
||||
|
||||
public Selection(CSGNode csgNode, Plane plane) {
|
||||
public Selection(CSGNode csgNode, Polygon poly) {
|
||||
this.csgNode = csgNode;
|
||||
this.plane = plane;
|
||||
this.poly = poly;
|
||||
}
|
||||
|
||||
public boolean sameTo(CSGNode csgNode, Plane plane) {
|
||||
return this.csgNode.equals(csgNode) && this.plane.equals(plane);
|
||||
public boolean sameTo(CSGNode csgNode, Polygon poly) {
|
||||
return this.csgNode.equals(csgNode) && this.poly.equals(poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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;
|
||||
|
|
@ -15,7 +14,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class Plane {
|
||||
public class Polygon {
|
||||
|
||||
public final Vector normal;
|
||||
public final List<Vector> shell;
|
||||
|
|
@ -23,15 +22,15 @@ public class Plane {
|
|||
|
||||
private List<Vector[]> triangles;
|
||||
|
||||
public Plane(List<Vector> shell) {
|
||||
public Polygon(List<Vector> shell) {
|
||||
this(shell, Collections.emptyList());
|
||||
}
|
||||
|
||||
public Plane(List<Vector> shell, List<List<Vector>> holes) {
|
||||
public Polygon(List<Vector> shell, List<List<Vector>> holes) {
|
||||
this(normalOfCCWSeq(shell.get(0), shell.get(1), shell.get(2)), shell, holes);
|
||||
}
|
||||
|
||||
public Plane(Vector normal, List<Vector> shell, List<List<Vector>> holes) {
|
||||
public Polygon(Vector normal, List<Vector> shell, List<List<Vector>> holes) {
|
||||
this.normal = normal.normalize();
|
||||
this.shell = shell;
|
||||
this.holes = holes;
|
||||
|
|
@ -43,11 +42,11 @@ public class Plane {
|
|||
}
|
||||
}
|
||||
|
||||
public Plane fixCCW() {
|
||||
public Polygon 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 Plane(normal, shell, holes);
|
||||
return new Polygon(normal, shell, holes);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
@ -82,7 +81,7 @@ public class Plane {
|
|||
.map(vector -> new PolygonPoint(vector.x, vector.y, vector.z))
|
||||
.collect(toList());
|
||||
|
||||
Polygon polygon = new Polygon(shellPoints);
|
||||
org.poly2tri.geometry.polygon.Polygon polygon = new org.poly2tri.geometry.polygon.Polygon(shellPoints);
|
||||
|
||||
for (List<Vector> hole : holes) {
|
||||
|
||||
|
|
@ -91,7 +90,7 @@ public class Plane {
|
|||
.map(vector -> new PolygonPoint(vector.x, vector.y, vector.z))
|
||||
.collect(toList());
|
||||
|
||||
polygon.addHole(new Polygon(holePoints));
|
||||
polygon.addHole(new org.poly2tri.geometry.polygon.Polygon(holePoints));
|
||||
}
|
||||
|
||||
Poly2Tri.triangulate(polygon);
|
||||
|
|
@ -128,11 +127,11 @@ public class Plane {
|
|||
triangle[2] = first;
|
||||
}
|
||||
|
||||
public Plane flip() {
|
||||
return new Plane(normal.negate(), shell, holes);
|
||||
public Polygon flip() {
|
||||
return new Polygon(normal.negate(), shell, holes);
|
||||
}
|
||||
|
||||
public static List<Plane> extrude(Plane source, Vector target) {
|
||||
public static List<Polygon> extrude(Polygon source, Vector target) {
|
||||
|
||||
double dotProduct = target.normalize().dot(source.normal);
|
||||
if (dotProduct == 0) {
|
||||
|
|
@ -143,22 +142,22 @@ public class Plane {
|
|||
}
|
||||
source = source.fixCCW();
|
||||
|
||||
List<Plane> planes = new ArrayList<>();
|
||||
planes.add(source);
|
||||
List<Polygon> poly = new ArrayList<>();
|
||||
poly.add(source);
|
||||
|
||||
Plane lid = source.shift(target).flip();
|
||||
planes.add(lid);
|
||||
Polygon lid = source.shift(target).flip();
|
||||
poly.add(lid);
|
||||
|
||||
for (int i = 0; i < source.shell.size(); i++) {
|
||||
Plane face = new Plane(Arrays.asList(
|
||||
Polygon face = new Polygon(Arrays.asList(
|
||||
get(source.shell, i - 1),
|
||||
get(lid.shell, i - 1),
|
||||
get(lid.shell, i),
|
||||
get(source.shell, i)
|
||||
));
|
||||
planes.add(face);
|
||||
poly.add(face);
|
||||
}
|
||||
return planes;
|
||||
return poly;
|
||||
}
|
||||
|
||||
public static <T> T get(List<T> list, int i) {
|
||||
|
|
@ -169,12 +168,12 @@ public class Plane {
|
|||
return list.get(i);
|
||||
}
|
||||
|
||||
public Plane shift(Vector target) {
|
||||
public Polygon 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 Plane(normal, shell, holes);
|
||||
return new Polygon(normal, shell, holes);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,11 +8,11 @@ import java.util.List;
|
|||
|
||||
public class Sketch {
|
||||
|
||||
public final Plane owner;
|
||||
public final Polygon owner;
|
||||
public final List<List<Vector>> polygons = new ArrayList<>();
|
||||
public final Group drawLayer = new Group();
|
||||
|
||||
public Sketch(Plane owner) {
|
||||
public Sketch(Polygon owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,16 +32,16 @@ public class Utils3D {
|
|||
}
|
||||
|
||||
|
||||
public static CSGMesh getMesh(List<Plane> planes) {
|
||||
public static CSGMesh getMesh(List<Polygon> polygons) {
|
||||
|
||||
CSGMesh mesh = new CSGMesh();
|
||||
|
||||
int faceCounter = 0;
|
||||
|
||||
for (Plane plane : planes) {
|
||||
for (Polygon poly : polygons) {
|
||||
|
||||
|
||||
for (Vector[] triangle : plane.getTriangles()) {
|
||||
for (Vector[] triangle : poly.getTriangles()) {
|
||||
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
|
|
@ -82,7 +82,7 @@ public class Utils3D {
|
|||
counter + 2, // third vertex
|
||||
0 // texture (not covered)
|
||||
);
|
||||
mesh.polygons.put(faceCounter, plane);
|
||||
mesh.polygons.put(faceCounter, poly);
|
||||
++faceCounter;
|
||||
|
||||
} // end if #verts >= 3
|
||||
|
|
@ -147,12 +147,12 @@ public class Utils3D {
|
|||
return mesh;
|
||||
}
|
||||
|
||||
public static List<Plane> createCube(double width) {
|
||||
Plane square = createSquare(width);
|
||||
return Plane.extrude(square, square.normal.scale(width));
|
||||
public static List<Polygon> createCube(double width) {
|
||||
Polygon square = createSquare(width);
|
||||
return Polygon.extrude(square, square.normal.scale(width));
|
||||
}
|
||||
|
||||
public static Plane createSquare(double width) {
|
||||
public static Polygon createSquare(double width) {
|
||||
|
||||
width /= 2;
|
||||
|
||||
|
|
@ -173,6 +173,6 @@ public class Utils3D {
|
|||
//
|
||||
// polygon.addHole(hole);
|
||||
|
||||
return new Plane(shell);
|
||||
return new Polygon(shell);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
477
src/cad/gl/BBox.java
Normal file
477
src/cad/gl/BBox.java
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
public class BBox {
|
||||
private double minX;
|
||||
private double maxX;
|
||||
private double minY;
|
||||
private double maxY;
|
||||
private double minZ;
|
||||
private double maxZ;
|
||||
|
||||
/**
|
||||
* Create an axis aligned bounding box object, with an empty bounds
|
||||
* where maxX < minX, maxY < minY and maxZ < minZ.
|
||||
*/
|
||||
public BBox() {
|
||||
minX = minY = minZ = 0.0f;
|
||||
maxX = maxY = maxZ = -1.0f;
|
||||
}
|
||||
|
||||
public BBox copy() {
|
||||
return new BBox(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an axis aligned bounding box based on the minX, minY, minZ, maxX, maxY,
|
||||
* and maxZ values specified.
|
||||
*/
|
||||
public BBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an axis aligned bounding box as a copy of the specified
|
||||
* BoxBounds object.
|
||||
*/
|
||||
public BBox(BBox other) {
|
||||
setBounds(other);
|
||||
}
|
||||
|
||||
|
||||
public boolean is2D() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for getting the width of this bounds.
|
||||
* The dimension along the X-Axis.
|
||||
*/
|
||||
public double getWidth() {
|
||||
return maxX - minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for getting the height of this bounds.
|
||||
* The dimension along the Y-Axis.
|
||||
*/
|
||||
public double getHeight() {
|
||||
return maxY - minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for getting the depth of this bounds.
|
||||
* The dimension along the Z-Axis.
|
||||
*/
|
||||
public double getDepth() {
|
||||
return maxZ - minZ;
|
||||
}
|
||||
|
||||
public double getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
public void setMinX(double minX) {
|
||||
this.minX = minX;
|
||||
}
|
||||
|
||||
public double getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
public void setMinY(double minY) {
|
||||
this.minY = minY;
|
||||
}
|
||||
|
||||
public double getMinZ() {
|
||||
return minZ;
|
||||
}
|
||||
|
||||
public void setMinZ(double minZ) {
|
||||
this.minZ = minZ;
|
||||
}
|
||||
|
||||
public double getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
public void setMaxX(double maxX) {
|
||||
this.maxX = maxX;
|
||||
}
|
||||
|
||||
public double getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
public void setMaxY(double maxY) {
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
public double getMaxZ() {
|
||||
return maxZ;
|
||||
}
|
||||
|
||||
public void setMaxZ(double maxZ) {
|
||||
this.maxZ = maxZ;
|
||||
}
|
||||
|
||||
public Vector getMin(Vector min) {
|
||||
if (min == null) {
|
||||
min = new Vector();
|
||||
}
|
||||
min.x = minX;
|
||||
min.y = minY;
|
||||
min.z = minZ;
|
||||
return min;
|
||||
|
||||
}
|
||||
|
||||
public Vector getMax(Vector max) {
|
||||
if (max == null) {
|
||||
max = new Vector();
|
||||
}
|
||||
max.x = maxX;
|
||||
max.y = maxY;
|
||||
max.z = maxZ;
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
public BBox deriveWithUnion(BBox other) {
|
||||
unionWith(other);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BBox deriveWithNewBounds(BBox other) {
|
||||
if (other.isEmpty()) {
|
||||
return makeEmpty();
|
||||
}
|
||||
minX = other.getMinX();
|
||||
minY = other.getMinY();
|
||||
minZ = other.getMinZ();
|
||||
maxX = other.getMaxX();
|
||||
maxY = other.getMaxY();
|
||||
maxZ = other.getMaxZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public BBox deriveWithNewBounds(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
if ((maxX < minX) || (maxY < minY) || (maxZ < minZ)) {
|
||||
return makeEmpty();
|
||||
}
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.minZ = minZ;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
this.maxZ = maxZ;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BBox deriveWithNewBoundsAndSort(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
setBoundsAndSort(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bounds to match that of the BoxBounds object specified. The
|
||||
* specified bounds object must not be null.
|
||||
*/
|
||||
public final void setBounds(BBox other) {
|
||||
minX = other.getMinX();
|
||||
minY = other.getMinY();
|
||||
minZ = other.getMinZ();
|
||||
maxX = other.getMaxX();
|
||||
maxY = other.getMaxY();
|
||||
maxZ = other.getMaxZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bounds to the given values.
|
||||
*/
|
||||
public final void setBounds(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.minZ = minZ;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
this.maxZ = maxZ;
|
||||
}
|
||||
|
||||
public void setBoundsAndSort(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
sortMinMax();
|
||||
}
|
||||
|
||||
public void setBoundsAndSort(Vector p1, Vector p2) {
|
||||
setBoundsAndSort(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
|
||||
}
|
||||
|
||||
public void unionWith(BBox other) {
|
||||
// Short circuit union if either bounds is empty.
|
||||
if (other.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
setBounds(other);
|
||||
return;
|
||||
}
|
||||
|
||||
minX = Math.min(minX, other.getMinX());
|
||||
minY = Math.min(minY, other.getMinY());
|
||||
minZ = Math.min(minZ, other.getMinZ());
|
||||
maxX = Math.max(maxX, other.getMaxX());
|
||||
maxY = Math.max(maxY, other.getMaxY());
|
||||
maxZ = Math.max(maxZ, other.getMaxZ());
|
||||
}
|
||||
|
||||
|
||||
public void unionWith(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
// Short circuit union if either bounds is empty.
|
||||
if ((maxX < minX) || (maxY < minY) || (maxZ < minZ)) {
|
||||
return;
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
return;
|
||||
}
|
||||
|
||||
this.minX = Math.min(this.minX, minX);
|
||||
this.minY = Math.min(this.minY, minY);
|
||||
this.minZ = Math.min(this.minZ, minZ);
|
||||
this.maxX = Math.max(this.maxX, maxX);
|
||||
this.maxY = Math.max(this.maxY, maxY);
|
||||
this.maxZ = Math.max(this.maxZ, maxZ);
|
||||
}
|
||||
|
||||
public void add(double x, double y, double z) {
|
||||
unionWith(x, y, z, x, y, z);
|
||||
}
|
||||
|
||||
public void add(Vector p) {
|
||||
add(p.x, p.y, p.z);
|
||||
}
|
||||
|
||||
public void intersectWith(BBox other) {
|
||||
// Short circuit intersect if either bounds is empty.
|
||||
if (this.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (other.isEmpty()) {
|
||||
makeEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
minX = Math.max(minX, other.getMinX());
|
||||
minY = Math.max(minY, other.getMinY());
|
||||
minZ = Math.max(minZ, other.getMinZ());
|
||||
maxX = Math.min(maxX, other.getMaxX());
|
||||
maxY = Math.min(maxY, other.getMaxY());
|
||||
maxZ = Math.min(maxZ, other.getMaxZ());
|
||||
}
|
||||
|
||||
public void intersectWith(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
// Short circuit intersect if either bounds is empty.
|
||||
if (this.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if ((maxX < minX) || (maxY < minY) || (maxZ < minZ)) {
|
||||
makeEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
this.minX = Math.max(this.minX, minX);
|
||||
this.minY = Math.max(this.minY, minY);
|
||||
this.minZ = Math.max(this.minZ, minZ);
|
||||
this.maxX = Math.min(this.maxX, maxX);
|
||||
this.maxY = Math.min(this.maxY, maxY);
|
||||
this.maxZ = Math.min(this.maxZ, maxZ);
|
||||
}
|
||||
|
||||
public boolean contains(Vector p) {
|
||||
if ((p == null) || isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return contains(p.x, p.y, p.z);
|
||||
}
|
||||
|
||||
public boolean contains(double x, double y, double z) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (x >= minX && x <= maxX && y >= minY && y <= maxY
|
||||
&& z >= minZ && z <= maxZ);
|
||||
}
|
||||
|
||||
public boolean contains(double x, double y, double z,
|
||||
double width, double height, double depth) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return contains(x, y, z) && contains(x + width, y + height, z + depth);
|
||||
}
|
||||
|
||||
public boolean intersects(double x, double y, double z,
|
||||
double width, double height, double depth) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (x + width >= minX &&
|
||||
y + height >= minY &&
|
||||
z + depth >= minZ &&
|
||||
x <= maxX &&
|
||||
y <= maxY &&
|
||||
z <= maxZ);
|
||||
}
|
||||
|
||||
public boolean intersects(BBox other) {
|
||||
if ((other == null) || other.isEmpty() || isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (other.getMaxX() >= minX &&
|
||||
other.getMaxY() >= minY &&
|
||||
other.getMaxZ() >= minZ &&
|
||||
other.getMinX() <= maxX &&
|
||||
other.getMinY() <= maxY &&
|
||||
other.getMinZ() <= maxZ);
|
||||
}
|
||||
|
||||
public boolean disjoint(double x, double y, double width, double height) {
|
||||
return disjoint(x, y, 0f, width, height, 0f);
|
||||
}
|
||||
|
||||
public boolean disjoint(double x, double y, double z,
|
||||
double width, double height, double depth) {
|
||||
if (isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return (x + width < minX ||
|
||||
y + height < minY ||
|
||||
z + depth < minZ ||
|
||||
x > maxX ||
|
||||
y > maxY ||
|
||||
z > maxZ);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return maxX < minX || maxY < minY || maxZ < minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the edges of this BoxBounds "outward" toward integral boundaries,
|
||||
* such that the rounded bounding box will always full enclose the original
|
||||
* bounding box.
|
||||
*/
|
||||
public void roundOut() {
|
||||
minX = Math.floor(minX);
|
||||
minY = Math.floor(minY);
|
||||
minZ = Math.floor(minZ);
|
||||
maxX = Math.ceil(maxX);
|
||||
maxY = Math.ceil(maxY);
|
||||
maxZ = Math.ceil(maxZ);
|
||||
}
|
||||
|
||||
public void grow(double h, double v, double d) {
|
||||
minX -= h;
|
||||
maxX += h;
|
||||
minY -= v;
|
||||
maxY += v;
|
||||
minZ -= d;
|
||||
maxZ += d;
|
||||
}
|
||||
|
||||
public BBox deriveWithPadding(double h, double v, double d) {
|
||||
grow(h, v, d);
|
||||
return this;
|
||||
}
|
||||
|
||||
// for convenience, this function returns a reference to itself, so we can
|
||||
// change from using "bounds.makeEmpty(); return bounds;" to just
|
||||
// "return bounds.makeEmpty()"
|
||||
public BBox makeEmpty() {
|
||||
minX = minY = minZ = 0.0f;
|
||||
maxX = maxY = maxZ = -1.0f;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void sortMinMax() {
|
||||
if (minX > maxX) {
|
||||
double tmp = maxX;
|
||||
maxX = minX;
|
||||
minX = tmp;
|
||||
}
|
||||
if (minY > maxY) {
|
||||
double tmp = maxY;
|
||||
maxY = minY;
|
||||
minY = tmp;
|
||||
}
|
||||
if (minZ > maxZ) {
|
||||
double tmp = maxZ;
|
||||
maxZ = minZ;
|
||||
minZ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
public void translate(double x, double y, double z) {
|
||||
setMinX(getMinX() + x);
|
||||
setMinY(getMinY() + y);
|
||||
setMaxX(getMaxX() + x);
|
||||
setMaxY(getMaxY() + y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final BBox other = (BBox) obj;
|
||||
if (minX != other.getMinX()) {
|
||||
return false;
|
||||
}
|
||||
if (minY != other.getMinY()) {
|
||||
return false;
|
||||
}
|
||||
if (minZ != other.getMinZ()) {
|
||||
return false;
|
||||
}
|
||||
if (maxX != other.getMaxX()) {
|
||||
return false;
|
||||
}
|
||||
if (maxY != other.getMaxY()) {
|
||||
return false;
|
||||
}
|
||||
if (maxZ != other.getMaxZ()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long hash = 7;
|
||||
hash = 79 * hash + Double.doubleToLongBits(minX);
|
||||
hash = 79 * hash + Double.doubleToLongBits(minY);
|
||||
hash = 79 * hash + Double.doubleToLongBits(minZ);
|
||||
hash = 79 * hash + Double.doubleToLongBits(maxX);
|
||||
hash = 79 * hash + Double.doubleToLongBits(maxY);
|
||||
hash = 79 * hash + Double.doubleToLongBits(maxZ);
|
||||
|
||||
return (int) hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BBox { minX:" + minX + ", minY:" + minY + ", minZ:" + minZ + ", maxX:" + maxX + ", maxY:" + maxY + ", maxZ:" + maxZ + "}";
|
||||
}
|
||||
}
|
||||
16
src/cad/gl/Camera.java
Normal file
16
src/cad/gl/Camera.java
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package cad.gl;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class Camera {
|
||||
|
||||
public float aspect = 1;
|
||||
public double near = 5.0f;
|
||||
public double far = 60.0f;
|
||||
|
||||
public int sceneW;
|
||||
public int sceneH;
|
||||
|
||||
public double near_width = 1;
|
||||
}
|
||||
20
src/cad/gl/CompiledNode.java
Normal file
20
src/cad/gl/CompiledNode.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package cad.gl;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class CompiledNode {
|
||||
|
||||
public final int glId;
|
||||
public final Node node;
|
||||
|
||||
public CompiledNode(Node node, GL2 gl) {
|
||||
this.node = node;
|
||||
glId = gl.glGenLists(1);
|
||||
gl.glNewList(glId, GL2.GL_COMPILE);
|
||||
node.draw(gl);
|
||||
gl.glEndList();
|
||||
}
|
||||
}
|
||||
230
src/cad/gl/MeshNode.java
Normal file
230
src/cad/gl/MeshNode.java
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.fx.Polygon;
|
||||
import cad.math.Vector;
|
||||
import com.sun.javafx.scene.input.PickResultChooser;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.input.PickResult;
|
||||
import javafx.scene.shape.CullFace;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class MeshNode extends Node {
|
||||
|
||||
public final List<Polygon> faces;
|
||||
|
||||
static boolean DRAW_LINES = false;
|
||||
private BBox cachedBounds;
|
||||
|
||||
public MeshNode(List<Polygon> faces) {
|
||||
this.faces = faces;
|
||||
}
|
||||
|
||||
@Override
|
||||
void draw(GL2 gl) {
|
||||
for (Polygon face : faces) {
|
||||
|
||||
//http://devernay.free.fr/cours/opengl/materials.html
|
||||
// float[] amb = {0f, 0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, amb, 0);
|
||||
|
||||
float[] diff = {0.6901961f, 0.76862746f, 0.87058824f};
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, diff, 0);
|
||||
|
||||
// float[] spec = {0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, spec, 0);
|
||||
// float shine = 0.6f;
|
||||
// gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shine * 128.0f);
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
|
||||
gl.glNormal3d(face.normal.x, face.normal.y, face.normal.z); //very important!!
|
||||
for (Vector[] tr : face.getTriangles()) {
|
||||
gl.glVertex3d(tr[0].x, tr[0].y, tr[0].z);
|
||||
gl.glVertex3d(tr[1].x, tr[1].y, tr[1].z);
|
||||
gl.glVertex3d(tr[2].x, tr[2].y, tr[2].z);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
if (DRAW_LINES) {
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glNormal3d(face.normal.x, face.normal.y, face.normal.z);
|
||||
for (int i = 0; i < face.shell.size(); i++) {
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
Vector a = Polygon.get(face.shell, i);
|
||||
Vector b = Polygon.get(face.shell, i + 1);
|
||||
gl.glVertex3d(a.x, a.y, a.z);
|
||||
gl.glVertex3d(b.x, b.y, b.z);
|
||||
gl.glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BBox computeBounds() {
|
||||
if (cachedBounds == null) {
|
||||
cachedBounds = new BBox();
|
||||
for (Polygon face : faces) {
|
||||
for (Vector vector : face.shell) {
|
||||
cachedBounds.add(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cachedBounds;
|
||||
}
|
||||
|
||||
protected boolean impl_computeIntersects(PickRay pickRay, PickResultChooser pickResult,
|
||||
javafx.scene.Node candidate, CullFace cullFace,
|
||||
boolean reportFace) {
|
||||
|
||||
boolean found = false;
|
||||
|
||||
final Vector o = pickRay.getOriginNoClone();
|
||||
final Vector d = pickRay.getDirectionNoClone();
|
||||
|
||||
for (Polygon face : faces) {
|
||||
for (Vector[] triangle : face.getTriangles()) {
|
||||
if (computeIntersectsFace(pickRay, o, d, triangle, cullFace, candidate,
|
||||
reportFace, pickResult)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private Point3D computeCentroid(
|
||||
double v0x, double v0y, double v0z,
|
||||
double v1x, double v1y, double v1z,
|
||||
double v2x, double v2y, double v2z) {
|
||||
|
||||
// Point3D center = v1.midpoint(v2);
|
||||
// Point3D vec = center.subtract(v0);
|
||||
// return v0.add(new Point3D(vec.getX() / 3.0, vec.getY() / 3.0, vec.getZ() / 3.0));
|
||||
|
||||
return new Point3D(
|
||||
v0x + (v2x + (v1x - v2x) / 2.0 - v0x) / 3.0,
|
||||
v0y + (v2y + (v1y - v2y) / 2.0 - v0y) / 3.0,
|
||||
v0z + (v2z + (v1z - v2z) / 2.0 - v0z) / 3.0);
|
||||
}
|
||||
|
||||
private boolean computeIntersectsFace(
|
||||
PickRay pickRay, Vector origin, Vector dir, Vector[] face,
|
||||
CullFace cullFace, javafx.scene.Node candidate, boolean reportFace,
|
||||
PickResultChooser result) {//, BoxBounds rayBounds) {
|
||||
|
||||
final float v0x = (float) face[0].x;
|
||||
final float v0y = (float) face[0].y;
|
||||
final float v0z = (float) face[0].z;
|
||||
final float v1x = (float) face[1].x;
|
||||
final float v1y = (float) face[1].y;
|
||||
final float v1z = (float) face[1].z;
|
||||
final float v2x = (float) face[2].x;
|
||||
final float v2y = (float) face[2].y;
|
||||
final float v2z = (float) face[2].z;
|
||||
|
||||
// e1 = v1.subtract(v0)
|
||||
final float e1x = v1x - v0x;
|
||||
final float e1y = v1y - v0y;
|
||||
final float e1z = v1z - v0z;
|
||||
// e2 = v2.subtract(v0)
|
||||
final float e2x = v2x - v0x;
|
||||
final float e2y = v2y - v0y;
|
||||
final float e2z = v2z - v0z;
|
||||
|
||||
// h = dir.crossProduct(e2)
|
||||
final double hx = dir.y * e2z - dir.z * e2y;
|
||||
final double hy = dir.z * e2x - dir.x * e2z;
|
||||
final double hz = dir.x * e2y - dir.y * e2x;
|
||||
|
||||
// a = e1.dotProduct(h)
|
||||
final double a = e1x * hx + e1y * hy + e1z * hz;
|
||||
if (a == 0.0) {
|
||||
return false;
|
||||
}
|
||||
final double f = 1.0 / a;
|
||||
|
||||
// s = origin.subtract(v0)
|
||||
final double sx = origin.x - v0x;
|
||||
final double sy = origin.y - v0y;
|
||||
final double sz = origin.z - v0z;
|
||||
|
||||
// u = f * (s.dotProduct(h))
|
||||
final double u = f * (sx * hx + sy * hy + sz * hz);
|
||||
|
||||
if (u < 0.0 || u > 1.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// q = s.crossProduct(e1)
|
||||
final double qx = sy * e1z - sz * e1y;
|
||||
final double qy = sz * e1x - sx * e1z;
|
||||
final double qz = sx * e1y - sy * e1x;
|
||||
|
||||
// v = f * dir.dotProduct(q)
|
||||
double v = f * (dir.x * qx + dir.y * qy + dir.z * qz);
|
||||
|
||||
if (v < 0.0 || u + v > 1.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// t = f * e2.dotProduct(q)
|
||||
final double t = f * (e2x * qx + e2y * qy + e2z * qz);
|
||||
|
||||
if (t >= pickRay.getNearClip() && t <= pickRay.getFarClip()) {
|
||||
// This branch is entered only for hit triangles (not so often),
|
||||
// so we can get smoothly back to the nice code using Point3Ds.
|
||||
|
||||
if (cullFace != CullFace.NONE) {
|
||||
// normal = e1.crossProduct(e2)
|
||||
final Point3D normal = new Point3D(
|
||||
e1y * e2z - e1z * e2y,
|
||||
e1z * e2x - e1x * e2z,
|
||||
e1x * e2y - e1y * e2x);
|
||||
|
||||
final double nangle = normal.angle(
|
||||
new Point3D(-dir.x, -dir.y, -dir.z));
|
||||
if ((nangle >= 90 || cullFace != CullFace.BACK) &&
|
||||
(nangle <= 90 || cullFace != CullFace.FRONT)) {
|
||||
// hit culled face
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Double.isInfinite(t) || Double.isNaN(t)) {
|
||||
// we've got a nonsense pick ray or triangle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result == null || !result.isCloser(t)) {
|
||||
// it intersects, but we are not interested in the result
|
||||
// or we already have a better (closer) result
|
||||
// so we can omit the point and texture computation
|
||||
return true;
|
||||
}
|
||||
|
||||
// Point3D point = PickResultChooser.computePoint(pickRay, t);
|
||||
|
||||
// result.offer(candidate, t,
|
||||
// reportFace ? faceIndex / vertexFormat.getFaceElementSize() : PickResult.FACE_UNDEFINED,
|
||||
// point, txCoords);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
27
src/cad/gl/Node.java
Normal file
27
src/cad/gl/Node.java
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package cad.gl;
|
||||
|
||||
import com.sun.javafx.geom.PickRay;
|
||||
import com.sun.javafx.scene.input.PickResultChooser;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
|
||||
public abstract class Node {
|
||||
|
||||
abstract void draw(GL2 gl);
|
||||
|
||||
// protected final boolean impl_intersects(PickRay pickRay, PickResultChooser pickResult) {
|
||||
// double boundsDistance = impl_intersectsBounds(pickRay);
|
||||
// if (!Double.isNaN(boundsDistance)) {
|
||||
// if (isPickOnBounds()) {
|
||||
// if (pickResult != null) {
|
||||
// pickResult.offer(this, boundsDistance, PickResultChooser.computePoint(pickRay, boundsDistance));
|
||||
// }
|
||||
// return true;
|
||||
// } else {
|
||||
// return impl_computeIntersects(pickRay, pickResult);
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
}
|
||||
152
src/cad/gl/PickRay.java
Normal file
152
src/cad/gl/PickRay.java
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
package cad.gl;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
/**
|
||||
* A ray used for picking.
|
||||
*/
|
||||
public class PickRay {
|
||||
private Vector origin = new Vector();
|
||||
private Vector direction = new Vector();
|
||||
private double nearClip = 0.0;
|
||||
private double farClip = Double.POSITIVE_INFINITY;
|
||||
|
||||
// static final double EPS = 1.0e-13;
|
||||
static final double EPS = 1.0e-5f;
|
||||
|
||||
public PickRay() {
|
||||
}
|
||||
|
||||
public PickRay(Vector origin, Vector direction, double nearClip, double farClip) {
|
||||
set(origin, direction, nearClip, farClip);
|
||||
}
|
||||
|
||||
public PickRay(double x, double y, double z, double nearClip, double farClip) {
|
||||
set(x, y, z, nearClip, farClip);
|
||||
}
|
||||
|
||||
|
||||
public final void set(Vector origin, Vector direction, double nearClip, double farClip) {
|
||||
setOrigin(origin);
|
||||
setDirection(direction);
|
||||
this.nearClip = nearClip;
|
||||
this.farClip = farClip;
|
||||
}
|
||||
|
||||
public final void set(double x, double y, double z, double nearClip, double farClip) {
|
||||
setOrigin(x, y, -z);
|
||||
setDirection(0, 0, z);
|
||||
this.nearClip = nearClip;
|
||||
this.farClip = farClip;
|
||||
}
|
||||
|
||||
|
||||
public void setPickRay(PickRay other) {
|
||||
setOrigin(other.origin);
|
||||
setDirection(other.direction);
|
||||
nearClip = other.nearClip;
|
||||
farClip = other.farClip;
|
||||
}
|
||||
|
||||
public PickRay copy() {
|
||||
return new PickRay(origin, direction, nearClip, farClip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the pick ray in world coordinates.
|
||||
*
|
||||
* @param origin the origin (in world coordinates).
|
||||
*/
|
||||
public void setOrigin(Vector origin) {
|
||||
this.origin.set(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the pick ray in world coordinates.
|
||||
*
|
||||
* @param x the origin X coordinate
|
||||
* @param y the origin Y coordinate
|
||||
* @param z the origin Z coordinate
|
||||
*/
|
||||
public void setOrigin(double x, double y, double z) {
|
||||
this.origin.set(x, y, z);
|
||||
}
|
||||
|
||||
public Vector getOrigin(Vector rv) {
|
||||
if (rv == null) {
|
||||
rv = new Vector();
|
||||
}
|
||||
rv.set(origin);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Vector getOriginNoClone() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction vector of the pick ray. This vector need not
|
||||
* be normalized.
|
||||
*
|
||||
* @param direction the direction vector
|
||||
*/
|
||||
public void setDirection(Vector direction) {
|
||||
this.direction.set(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction of the pick ray. The vector need not be normalized.
|
||||
*
|
||||
* @param x the direction X magnitude
|
||||
* @param y the direction Y magnitude
|
||||
* @param z the direction Z magnitude
|
||||
*/
|
||||
public void setDirection(double x, double y, double z) {
|
||||
this.direction.set(x, y, z);
|
||||
}
|
||||
|
||||
public Vector getDirection(Vector rv) {
|
||||
if (rv == null) {
|
||||
rv = new Vector();
|
||||
}
|
||||
rv.set(direction);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Vector getDirectionNoClone() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public double getNearClip() {
|
||||
return nearClip;
|
||||
}
|
||||
|
||||
public double getFarClip() {
|
||||
return farClip;
|
||||
}
|
||||
|
||||
public double distance(Vector iPnt) {
|
||||
double x = iPnt.x - origin.x;
|
||||
double y = iPnt.y - origin.y;
|
||||
double z = iPnt.z - origin.z;
|
||||
return Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
|
||||
private static final double EPSILON_ABSOLUTE = 1.0e-5;
|
||||
|
||||
static boolean almostZero(double a) {
|
||||
return ((a < EPSILON_ABSOLUTE) && (a > -EPSILON_ABSOLUTE));
|
||||
}
|
||||
|
||||
private static boolean isNonZero(double v) {
|
||||
return ((v > EPS) || (v < -EPS));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "origin: " + origin + " direction: " + direction;
|
||||
}
|
||||
}
|
||||
318
src/cad/gl/Scene.java
Normal file
318
src/cad/gl/Scene.java
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.fx.Polygon;
|
||||
import cad.math.Vector;
|
||||
import com.jogamp.newt.event.MouseEvent;
|
||||
import com.jogamp.newt.event.MouseListener;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
import com.sun.javafx.geom.*;
|
||||
import javafx.scene.input.PickResult;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.Threading;
|
||||
import javax.media.opengl.glu.GLU;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Scene implements GLEventListener, MouseListener {
|
||||
|
||||
private final List<Node> toCompile = new ArrayList<>();
|
||||
private final List<CompiledNode> scene = new ArrayList<>();
|
||||
private final GLWindow window;
|
||||
private final Camera camera = new Camera();
|
||||
private Vector[] pickRay = {new Vector(), new Vector()};
|
||||
private float winMouseY;
|
||||
private float winMouseX;
|
||||
private boolean pickRequest = false;
|
||||
|
||||
public Scene(GLWindow window) {
|
||||
this.window = window;
|
||||
window.addGLEventListener(this);
|
||||
}
|
||||
|
||||
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};
|
||||
float white[] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
private float view_rotx = 0.0f, view_roty = 0.0f, view_rotz = 0.0f;
|
||||
// private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 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(0);
|
||||
|
||||
float pos0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos0, 0);
|
||||
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
|
||||
compileNodes(gl);
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
window.addMouseListener(this);
|
||||
}
|
||||
|
||||
private void compileNodes(GL2 gl) {
|
||||
if (toCompile.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Node node : toCompile) {
|
||||
scene.add(new CompiledNode(node, gl));
|
||||
}
|
||||
}
|
||||
|
||||
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
camera.sceneW = width;
|
||||
camera.sceneH = height;
|
||||
camera.aspect = (float) height / (float) width;
|
||||
|
||||
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||
gl.glLoadIdentity();
|
||||
gl.glFrustum(-camera.near_width, camera.near_width,
|
||||
-camera.aspect * camera.near_width, camera.aspect * camera.near_width,
|
||||
camera.near, camera.far);
|
||||
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) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
|
||||
|
||||
gl.glClearColor(0.5019608f, 0.5019608f, 0.5019608f, 0f);
|
||||
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
||||
|
||||
gl.glPushMatrix();
|
||||
gl.glScalef(scale, scale, scale);
|
||||
|
||||
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);
|
||||
|
||||
updatePickRay(gl);
|
||||
|
||||
drawPickRay(gl);
|
||||
|
||||
for (CompiledNode cn : scene) {
|
||||
gl.glCallList(cn.glId);
|
||||
}
|
||||
|
||||
|
||||
gl.glPopMatrix();
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
private void updatePickRay(GL2 gl) {
|
||||
if (!pickRequest) {
|
||||
return;
|
||||
}
|
||||
pickRequest = false;
|
||||
float[] model = new float[16];
|
||||
float[] proj = new float[16];
|
||||
int[] viewport = new int[16];
|
||||
|
||||
gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
|
||||
gl.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, model, 0);
|
||||
gl.glGetFloatv(GL2.GL_PROJECTION_MATRIX, proj, 0);
|
||||
|
||||
float[] out = new float[3];
|
||||
float y = viewport[3] - winMouseY;
|
||||
glu.gluUnProject(winMouseX, y, 0, model, 0, proj, 0, viewport, 0, out, 0);
|
||||
pickRay[0].set3(out);
|
||||
|
||||
glu.gluUnProject(winMouseX, y, 1, model, 0, proj, 0, viewport, 0, out, 0);
|
||||
pickRay[1].set3(out);
|
||||
|
||||
pickRay[1] = pickRay[1].minus(pickRay[0]).scale(700);
|
||||
}
|
||||
|
||||
public static float[] fixW(float[] v) {
|
||||
float w = v[3];
|
||||
for (int i = 0; i < 4; i++)
|
||||
v[i] = v[i] / w;
|
||||
return v;
|
||||
}
|
||||
|
||||
private void drawPickRay(GL2 gl) {
|
||||
|
||||
if (pickRay != null) {
|
||||
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
// Vector a = pickRay;
|
||||
// Vector b = pickRay.plus(pickRay.normalize().scale(-60));
|
||||
vertex(gl, pickRay[0]);
|
||||
vertex(gl, pickRay[1]);
|
||||
System.out.println(Arrays.toString(pickRay));
|
||||
gl.glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void vertex(GL2 gl, Vector vector) {
|
||||
gl.glVertex3d(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
computePickRay(e.getX(), e.getY());
|
||||
update(window::display);
|
||||
pickRequest = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
int width = window.getWidth();
|
||||
int height = window.getHeight();
|
||||
|
||||
float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) width);
|
||||
float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
volatile boolean updating = false;
|
||||
|
||||
private void update(Runnable op) {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
Threading.invokeOnOpenGLThread(false, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
updating = true;
|
||||
op.run();
|
||||
} finally {
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
float scale = 1;
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseEvent e) {
|
||||
double scaleFactor = e.getRotation()[1] > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||
scale *= scaleFactor;
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
public void addNode(Node node) {
|
||||
toCompile.add(node);
|
||||
}
|
||||
|
||||
|
||||
// private PickResult pick(final double x, final double y) {
|
||||
// final PickRay pickRay = computePickRay(x, y);
|
||||
// final double mag = pickRay.getDirectionNoClone().length();
|
||||
// pickRay.getDirectionNoClone().normalize();
|
||||
// final PickResult res = pickNode(pickRay);
|
||||
// return res;
|
||||
// }
|
||||
|
||||
GLU glu = new GLU();
|
||||
|
||||
private void computePickRay(float mx, float my) {
|
||||
|
||||
// winMouseX = mx - camera.sceneW / 2;
|
||||
// winMouseY = (camera.sceneH - my) - camera.sceneH / 2;
|
||||
|
||||
winMouseX = mx;
|
||||
winMouseY = my;
|
||||
//
|
||||
//
|
||||
// float winY = (camera.sceneH - my) - camera.sceneH/2;
|
||||
// double norm_y = winY/(camera.sceneH/2);
|
||||
//
|
||||
// float winX = mx - camera.sceneW/2;
|
||||
// double norm_x = winX/(camera.sceneW/2);
|
||||
|
||||
//
|
||||
// double y = camera.near_width * norm_y * camera.aspect;
|
||||
// double x = camera.near_width * norm_x;
|
||||
// System.out.println(x + ":" + y);
|
||||
// return new Vector(x, y, camera.near);
|
||||
}
|
||||
|
||||
private PickResult pickNode(PickRay ray) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,14 @@ public class Vector {
|
|||
public double y;
|
||||
public double z;
|
||||
|
||||
public static Vector fromArr3(float[] data) {
|
||||
return new Vector(data[0], data[1], data[2]);
|
||||
}
|
||||
|
||||
public static Vector fromArr3(double[] data) {
|
||||
return new Vector(data[0], data[1], data[2]);
|
||||
}
|
||||
|
||||
public Vector() {
|
||||
}
|
||||
|
||||
|
|
@ -23,16 +31,26 @@ public class Vector {
|
|||
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 void set(Vector vector) {
|
||||
set(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
public void set(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public void set3(float[] data) {
|
||||
this.x = data[0];
|
||||
this.y = data[1];
|
||||
this.z = data[2];
|
||||
}
|
||||
|
||||
public void set3(double[] data) {
|
||||
this.x = data[0];
|
||||
this.y = data[1];
|
||||
this.z = data[2];
|
||||
}
|
||||
|
||||
public Vector scale(double factor) {
|
||||
|
|
@ -102,4 +120,5 @@ public class Vector {
|
|||
public Vector negate() {
|
||||
return scale(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue