package org.goko.tools.viewer.jogl.service; import java.nio.FloatBuffer; import java.util.List; import javax.media.opengl.GL2; import javax.vecmath.Color4f; import javax.vecmath.Matrix3d; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Tuple3d; import javax.vecmath.Tuple3f; import javax.vecmath.Tuple4d; import javax.vecmath.Tuple4f; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f; import org.apache.commons.collections.CollectionUtils; import org.goko.core.common.exception.GkException; import org.goko.core.common.exception.GkTechnicalException; import org.goko.core.common.measure.Units; import org.goko.core.common.measure.quantity.Length; import org.goko.core.common.measure.units.Unit; import org.goko.core.controller.IGCodeContextProvider; import org.goko.core.gcode.rs274ngcv3.context.GCodeContext; import org.goko.core.math.Tuple6b; import org.goko.core.viewer.renderer.IRendererProxy; import org.goko.tools.viewer.jogl.utils.render.grid.GraduatedGridRenderer; import org.goko.tools.viewer.jogl.utils.render.grid.IGridRenderer; /** * Utility class for Jogl rendering * * @author Psyko * */ public class JoglUtils { /** Default Jogl unit (by convention)*/ public static final Unit<Length> JOGL_UNIT = Units.MILLIMETRE; public static final String XY_GRID_ID = "GRID.XY"; public static final String XZ_GRID_ID = "GRID.XZ"; public static final String YZ_GRID_ID = "GRID.YZ"; public static final Vector3f X_AXIS = new Vector3f(1f,0f,0f); public static final Vector3f Y_AXIS = new Vector3f(0f,1f,0f); public static final Vector3f Z_AXIS = new Vector3f(0f,0f,1f); public static final Vector3f X_AXIS_NEGATIVE = new Vector3f(-1f,0f,0f); public static final Vector3f Y_AXIS_NEGATIVE = new Vector3f(0f,-1f,0f); public static final Vector3f Z_AXIS_NEGATIVE = new Vector3f(0f,0f,-1f); public static final Color4f X_COLOR = new Color4f(1f,0f,0f,1f); public static final Color4f Y_COLOR = new Color4f(0f,1f,0f,1f); public static final Color4f Z_COLOR = new Color4f(0f,0f,1f,1f); private static final Point3f DEFAULT_COLOR = new Point3f(0.8f,0.8f,0.8f); public static void drawPoint(GL2 gl,Tuple6b point) throws GkException { drawPoint(gl, point, DEFAULT_COLOR); } public static void drawPoint(GL2 gl,Tuple6b point, Point3f color) throws GkException { drawPoint(gl, point, color, 0); } public static void drawPoint(GL2 gl,Tuple6b point, Point3f color, int style) throws GkException { gl.glPushAttrib(GL2.GL_LINE_BIT); gl.glColor3d(color.x, color.y, color.z); Point3d startPoint = point.toPoint3d(JOGL_UNIT); gl.glLineWidth(1f); gl.glBegin(GL2.GL_LINES); gl.glVertex3d(startPoint.x-0.5, startPoint.y, startPoint.z); gl.glVertex3d(startPoint.x+0.5, startPoint.y, startPoint.z); gl.glVertex3d(startPoint.x, startPoint.y-0.5, startPoint.z); gl.glVertex3d(startPoint.x, startPoint.y+0.5, startPoint.z); gl.glVertex3d(startPoint.x, startPoint.y, startPoint.z-0.5); gl.glVertex3d(startPoint.x, startPoint.y, startPoint.z+0.5); gl.glEnd(); gl.glPopAttrib(); } public static void drawSegment(GL2 gl, Tuple6b start, Tuple6b end) throws GkException { drawSegment(gl, start, end, DEFAULT_COLOR); } public static void drawSegment(GL2 gl, Tuple6b start, Tuple6b end, Point3f color) throws GkException { drawSegment(gl, start, end, color, 0); } public static void drawSegment(GL2 gl, Tuple6b start, Tuple6b end, Point3f color, int style) throws GkException { gl.glPushAttrib(GL2.GL_LINE_BIT); Point3d startPoint = start.toPoint3d(JOGL_UNIT); Point3d endPoint = end.toPoint3d(JOGL_UNIT); gl.glLineWidth(1f); gl.glBegin(GL2.GL_LINES); gl.glColor3d(color.x, color.y, color.z); gl.glVertex3d(startPoint.x, startPoint.y, startPoint.z); gl.glVertex3d(endPoint.x, endPoint.y, endPoint.z); gl.glEnd(); gl.glPopAttrib(); } public static void drawCircle(GL2 gl, Tuple6b center, double radius, Vector3f plane, Point3f color) throws GkException { Point3d c = center.toPoint3d(JOGL_UNIT); gl.glLineWidth(1f); gl.glPushAttrib(GL2.GL_LINE_BIT); gl.glColor3f(color.x, color.y, color.z); gl.glBegin(GL2.GL_LINE_STRIP); // Adaptive points count int nbPoints = (int) Math.max(12, radius * 4); double deltaAngle = (Math.PI*2) / nbPoints; for(int i = 0; i <= nbPoints; i++){ gl.glVertex3d(c.x + radius * Math.cos(i*deltaAngle), c.y + radius * Math.sin(i*deltaAngle), c.z); } gl.glEnd(); gl.glPopAttrib(); } public static void drawArc(GL2 gl, Tuple6b start, Tuple6b end, Tuple6b center, Vector3f plane, int direction) throws GkException { drawArc(gl, start, end, center, plane, direction,DEFAULT_COLOR,0); } public static void drawArc(GL2 gl, Tuple6b start, Tuple6b end, Tuple6b center, Vector3f plane, int direction, Point3f color) throws GkException { drawArc(gl, start, end, center, plane, direction,color,0); } public static void drawArc(GL2 gl, Tuple6b startPoint, Tuple6b endPoint, Tuple6b centerPoint, Vector3f plane, int direction, Point3f color, int style) throws GkException { boolean clockwise = direction == IRendererProxy.ARC_CLOCKWISE; plane.normalize(); gl.glBegin(GL2.GL_LINE_STRIP); Point3d start = startPoint.toPoint3d(JOGL_UNIT); Point3d center = centerPoint.toPoint3d(JOGL_UNIT); Point3d end = endPoint.toPoint3d(JOGL_UNIT); Vector3d v1 = new Vector3d(start.x - center.x, start.y - center.y, start.z - center.z); Vector3d v2 = new Vector3d(end.x - center.x, end.y - center.y, end.z - center.z); gl.glColor3f(color.x, color.y, color.z); double smallestAngle = StrictMath.atan2(v1.y,v1.x) - StrictMath.atan2(v2.y,v2.x); double angle = smallestAngle ; // If smallestAngle < 0 then it is a counterclockwise angle. if(smallestAngle < 0){ if(clockwise){ // The angle is CCW but the command is CCW angle = - ( 2*Math.PI - Math.abs(smallestAngle) ); // In OpenGl when rotating, CW rotation = negative angle }else{ angle = Math.abs(smallestAngle); // In OpenGl when rotating, CCW rotation = positive angle } }else{ if(clockwise){ // The angle is CW and we have a CW command angle = - Math.abs(smallestAngle); // In OpenGl when rotating, CW rotation = negative angle }else{ // The angle is CW but we want the CCW command angle = 2*Math.PI - smallestAngle; } } int nbPoints = 8; // Adaptive points count double arcLength = Math.abs(angle * v1.length()); nbPoints = (int) (arcLength * 8 ); Matrix3d rot = new Matrix3d(); rot.rotZ(angle / (nbPoints + 1)); double dz = (end.z - start.z) / (nbPoints + 1); gl.glVertex3d(start.x, start.y , start.z); for(int i = 0; i < nbPoints; i++){ rot.transform(v1); gl.glVertex3d(center.x + v1.x, center.y + v1.y, start.z + i * dz); } gl.glColor3f(color.x, color.y, color.z); gl.glVertex3d(end.x, end.y, end.z); gl.glEnd(); } public static void drawLineStrip(GL2 gl, Tuple6b... points) throws GkException { // TODO Auto-generated method stub } public static void drawLineStrip(GL2 gl, Point3f color, Tuple6b... points) throws GkException { // TODO Auto-generated method stub } public static void drawLineStrip(GL2 gl, Point3f color, int style, Tuple6b... points) throws GkException { // TODO Auto-generated method stub } public static void drawXYZAxis(GL2 gl, Tuple6b position, Point3f xColor, Point3f yColor, Point3f zColor, double scale, String label, double charWidth) throws GkException { // gl.glLineWidth(1.5f); // GLUT glut = new GLUT(); // // Tuple6b zero = new Tuple6b(0, 0, 0); // Tuple6b xaxis = new Tuple6b(1 * scale, 0, 0); // Tuple6b yaxis = new Tuple6b(0, 1 * scale, 0); // Tuple6b zaxis = new Tuple6b(0, 0, 1 * scale); // gl.glPushMatrix(); // gl.glTranslated(position.getX().doubleValue(), position.getY().doubleValue(), position.getZ().doubleValue()); // // gl.glPushMatrix(); // drawSegment(gl, zero, xaxis, xColor); // gl.glTranslated(xaxis.getX().doubleValue() - 1, xaxis.getY().doubleValue(), xaxis.getZ().doubleValue()); // gl.glRotated(90, 0, 1, 0); // glut.glutSolidCone(0.5, 1, 8, 1); // gl.glPopMatrix(); // // gl.glPushMatrix(); // drawSegment(gl, zero, yaxis, yColor); // gl.glTranslated(yaxis.getX().doubleValue(), yaxis.getY().doubleValue() - 1, yaxis.getZ().doubleValue()); // gl.glRotated(-90, 1, 0, 0); // glut.glutSolidCone(0.5, 1, 8, 1); // gl.glPopMatrix(); // // gl.glPushMatrix(); // drawSegment(gl, zero, zaxis, zColor); // gl.glTranslated(zaxis.getX().doubleValue(), zaxis.getY().doubleValue(), zaxis.getZ().doubleValue() - 1); // glut.glutSolidCone(0.5, 1, 8, 1); // gl.glPopMatrix(); // if(StringUtils.isNotBlank(label)){ // gl.glPushMatrix(); // double textScale = charWidth / glut.glutStrokeWidth(GLUT.STROKE_MONO_ROMAN, ' '); // gl.glTranslated(1, 1, 0); // gl.glScaled(textScale, textScale, textScale); // glut.glutStrokeString(GLUT.STROKE_MONO_ROMAN, label); // gl.glPopMatrix(); // } // gl.glPopMatrix(); throw new GkTechnicalException("Not implemented"); } public static void drawXYZAxis(GL2 gl, Tuple6b position, Point3f xColor, Point3f yColor, Point3f zColor, double scale) throws GkException { drawXYZAxis(gl, position, xColor, yColor, zColor, scale, null, 1); } public static IGridRenderer drawXYGrid(IGCodeContextProvider<GCodeContext> gcodeContextProvider){ IGridRenderer xyGridRenderer = new GraduatedGridRenderer(JoglUtils.XY_GRID_ID, gcodeContextProvider); xyGridRenderer.setNormal(JoglUtils.Z_AXIS); xyGridRenderer.setHorizontalVector(JoglUtils.X_AXIS); xyGridRenderer.setVerticalVector(JoglUtils.Y_AXIS); xyGridRenderer.setHorizontalColor(JoglUtils.X_COLOR); xyGridRenderer.setVerticalColor(JoglUtils.Y_COLOR); return xyGridRenderer; } public static IGridRenderer drawXZGrid(IGCodeContextProvider<GCodeContext> gcodeContextProvider){ IGridRenderer xzGridRenderer = new GraduatedGridRenderer(JoglUtils.XZ_GRID_ID, gcodeContextProvider); xzGridRenderer.setNormal(JoglUtils.Y_AXIS); xzGridRenderer.setHorizontalVector(JoglUtils.X_AXIS); xzGridRenderer.setVerticalVector(JoglUtils.Z_AXIS); xzGridRenderer.setHorizontalColor(JoglUtils.X_COLOR); xzGridRenderer.setVerticalColor(JoglUtils.Z_COLOR); return xzGridRenderer; } public static IGridRenderer drawYZGrid(IGCodeContextProvider<GCodeContext> gcodeContextProvider){ IGridRenderer yzGridRenderer = new GraduatedGridRenderer(JoglUtils.YZ_GRID_ID, gcodeContextProvider); yzGridRenderer.setNormal(JoglUtils.X_AXIS); yzGridRenderer.setHorizontalVector(JoglUtils.Y_AXIS_NEGATIVE); yzGridRenderer.setVerticalVector(JoglUtils.Z_AXIS); yzGridRenderer.setHorizontalColor(JoglUtils.Y_COLOR); yzGridRenderer.setVerticalColor(JoglUtils.Z_COLOR); return yzGridRenderer; } /** * Generate a FloatBuffer with the given list of Tuple4d. * For each tuple4d, 4 float values will be added the the created buffer. * @param lstTuple4d the list of Tuple4d * @return a FloatBuffer */ public static FloatBuffer buildFloatBuffer4d(List<? extends Tuple4d> lstTuple4d){ FloatBuffer buffer = FloatBuffer.allocate( CollectionUtils.size(lstTuple4d) * 4); for (Tuple4d tuple4d : lstTuple4d) { buffer.put((float) tuple4d.x); buffer.put((float) tuple4d.y); buffer.put((float) tuple4d.z); buffer.put((float) tuple4d.w); } return buffer; } /** * Generate a FloatBuffer with the given list of Tuple4f. * For each tuple4f, 4 float values will be added the the created buffer. * @param lstTuple4d the list of Tuple4d * @return a FloatBuffer */ public static FloatBuffer buildFloatBuffer4f(List<? extends Tuple4f> lstTuple4f){ FloatBuffer buffer = FloatBuffer.allocate( CollectionUtils.size(lstTuple4f) * 4); for (Tuple4f tuple4d : lstTuple4f) { buffer.put(tuple4d.x); buffer.put(tuple4d.y); buffer.put(tuple4d.z); buffer.put(tuple4d.w); } return buffer; } /** * Generate a FloatBuffer with the given list of Tuple3d. * For each tuple3d, 3 float values will be added the the created buffer. * @param lstTuple4d the list of Tuple4d * @return a FloatBuffer */ public static FloatBuffer buildFloatBuffer3d(List<? extends Tuple3d> lstTuple){ FloatBuffer buffer = FloatBuffer.allocate( CollectionUtils.size(lstTuple) * 4); for (Tuple3d tuple3d : lstTuple) { buffer.put((float) tuple3d.x); buffer.put((float) tuple3d.y); buffer.put((float) tuple3d.z); buffer.put(1); } return buffer; } /** * Generate a FloatBuffer with the given list of Tuple3f. * For each tuple3f, 3 float values will be added the the created buffer. * @param lstTuple4d the list of Tuple4d * @return a FloatBuffer */ public static FloatBuffer buildFloatBuffer3f(List<? extends Tuple3f> lstTuple){ FloatBuffer buffer = FloatBuffer.allocate( CollectionUtils.size(lstTuple) * 4); for (Tuple3f tuple3f : lstTuple) { buffer.put(tuple3f.x); buffer.put(tuple3f.y); buffer.put(tuple3f.z); buffer.put(1); } return buffer; } }