From 77dc241c8016406917fa0e835057d1b92d4996a1 Mon Sep 17 00:00:00 2001 From: Martin Pernollet Date: Sun, 5 Oct 2014 00:42:56 +0200 Subject: [PATCH] Introduce basic 2d chart --- .../factories/ChartComponentFactory.java | 2 +- .../src/api/org/jzy3d/chart2d/Chart2d.java | 91 ++ .../chart2d/Chart2dComponentFactory.java | 47 + .../src/api/org/jzy3d/chart2d/View2d.java | 18 + .../jzy3d/chart2d/primitives/LineSerie2d.java | 63 ++ .../org/jzy3d/chart2d/primitives/Serie2d.java | 20 + .../primitives/SynchronizedLineStrip.java | 132 +++ .../jzy3d/plot3d/primitives/axes/AxeBox.java | 1008 +++++++++-------- .../primitives/axes/layout/AxeBoxLayout.java | 14 +- .../primitives/axes/layout/IAxeLayout.java | 5 + .../text/renderers/TextBitmapRenderer.java | 188 ++- .../org/jzy3d/plot3d/transform/Transform.java | 4 +- .../plot3d/transform/TranslateDrawable.java | 108 +- .../factories/AWTChartComponentFactory.java | 4 + 14 files changed, 1067 insertions(+), 637 deletions(-) create mode 100644 jzy3d-api/src/api/org/jzy3d/chart2d/Chart2d.java create mode 100644 jzy3d-api/src/api/org/jzy3d/chart2d/Chart2dComponentFactory.java create mode 100644 jzy3d-api/src/api/org/jzy3d/chart2d/View2d.java create mode 100644 jzy3d-api/src/api/org/jzy3d/chart2d/primitives/LineSerie2d.java create mode 100644 jzy3d-api/src/api/org/jzy3d/chart2d/primitives/Serie2d.java create mode 100644 jzy3d-api/src/api/org/jzy3d/plot3d/primitives/SynchronizedLineStrip.java diff --git a/jzy3d-api/src/api/org/jzy3d/chart/factories/ChartComponentFactory.java b/jzy3d-api/src/api/org/jzy3d/chart/factories/ChartComponentFactory.java index 845a4b83..1f41acf9 100644 --- a/jzy3d-api/src/api/org/jzy3d/chart/factories/ChartComponentFactory.java +++ b/jzy3d-api/src/api/org/jzy3d/chart/factories/ChartComponentFactory.java @@ -109,7 +109,7 @@ public class ChartComponentFactory implements IChartComponentFactory { public IScreenshotKeyController newScreenshotKeyController(Chart chart) { // trigger screenshot on 's' letter String file = SCREENSHOT_FOLDER + "capture-" - + Utils.dat2str(new Date()) + ".png"; + + Utils.dat2str(new Date(), "yyyy-MM-dd-HH-mm-ss") + ".png"; IScreenshotKeyController screenshot; if (!chart.getWindowingToolkit().equals("newt")) diff --git a/jzy3d-api/src/api/org/jzy3d/chart2d/Chart2d.java b/jzy3d-api/src/api/org/jzy3d/chart2d/Chart2d.java new file mode 100644 index 00000000..7715a01d --- /dev/null +++ b/jzy3d-api/src/api/org/jzy3d/chart2d/Chart2d.java @@ -0,0 +1,91 @@ +package org.jzy3d.chart2d; + +import java.util.HashMap; +import java.util.Map; + +import javax.media.opengl.GLCapabilities; + +import org.jzy3d.chart.AWTChart; +import org.jzy3d.chart.factories.IChartComponentFactory; +import org.jzy3d.chart.factories.IChartComponentFactory.Toolkit; +import org.jzy3d.chart2d.primitives.LineSerie2d; +import org.jzy3d.chart2d.primitives.Serie2d; +import org.jzy3d.maths.BoundingBox3d; +import org.jzy3d.plot3d.primitives.axes.layout.IAxeLayout; +import org.jzy3d.plot3d.primitives.axes.layout.renderers.DateTickRenderer; +import org.jzy3d.plot3d.rendering.canvas.Quality; +import org.jzy3d.plot3d.rendering.view.View; +import org.jzy3d.plot3d.rendering.view.ViewportMode; +import org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode; + +// TODO: +// AXEBOX ticks too long +// AXEBOX Y label sur le côté +// X Labels centrés +// +// Interface de LineSerie fournie par Chart2d package, using x, y float args + +public class Chart2d extends AWTChart{ + + public Chart2d() { + super(); + } + + public Chart2d(IChartComponentFactory factory, Quality quality, String windowingToolkit, GLCapabilities capabilities) { + super(factory, quality, windowingToolkit, capabilities); + } + + public Chart2d(IChartComponentFactory factory, Quality quality, String windowingToolkit) { + super(factory, quality, windowingToolkit); + } + + public Chart2d(IChartComponentFactory components, Quality quality) { + super(components, quality); + } + + public Chart2d(Quality quality, String windowingToolkit) { + super(quality, windowingToolkit); + } + + public Chart2d(Quality quality) { + super(quality); + } + + public Chart2d(String windowingToolkit) { + super(windowingToolkit); + } + + public Chart2d(float timeMax, float ymin, float ymax, String xlabel, String ylabel){ + this(new Chart2dComponentFactory(), Quality.Intermediate, Toolkit.newt.toString()); + + IAxeLayout axe = getAxeLayout(); + axe.setYAxeLabel(ylabel); + axe.setXAxeLabel( xlabel ); + axe.setZAxeLabelDisplayed(false); + + axe.setTickLineDisplayed(false); + + axe.setXTickRenderer( new DateTickRenderer( "mm:ss" ) ); + + + View view = getView(); + view.setViewPositionMode(ViewPositionMode.TOP); + view.setBoundManual(new BoundingBox3d(0, timeMax, ymin, ymax, -1, 1)); + view.setSquared(true); + view.getCamera().setViewportMode(ViewportMode.STRETCH_TO_FILL); + } + + public Serie2d getSerie(String name){ + Serie2d s = null; + if(!series.keySet().contains(name)){ + s = new LineSerie2d(name); + addDrawable(s.getDrawable()); + } + else{ + s = series.get(name); + } + return s; + } + + Map series = new HashMap(); +} diff --git a/jzy3d-api/src/api/org/jzy3d/chart2d/Chart2dComponentFactory.java b/jzy3d-api/src/api/org/jzy3d/chart2d/Chart2dComponentFactory.java new file mode 100644 index 00000000..2a094950 --- /dev/null +++ b/jzy3d-api/src/api/org/jzy3d/chart2d/Chart2dComponentFactory.java @@ -0,0 +1,47 @@ +package org.jzy3d.chart2d; + +import org.jzy3d.chart.Chart; +import org.jzy3d.chart.factories.AWTChartComponentFactory; +import org.jzy3d.chart.factories.IChartComponentFactory; +import org.jzy3d.plot3d.rendering.canvas.ICanvas; +import org.jzy3d.plot3d.rendering.canvas.Quality; +import org.jzy3d.plot3d.rendering.scene.Scene; +import org.jzy3d.plot3d.rendering.view.View; + +public class Chart2dComponentFactory extends AWTChartComponentFactory{ + @Override + public View newView(Scene scene, ICanvas canvas, Quality quality) { + return new View2d(this, scene, canvas, quality); + } + + + public static Chart chart() { + return chart(Quality.Intermediate); + } + + public static Chart chart(Quality quality) { + Chart2dComponentFactory f = new Chart2dComponentFactory(); + return f.newChart(quality, Toolkit.newt); + } + + public static Chart chart(String toolkit) { + Chart2dComponentFactory f = new Chart2dComponentFactory(); + return f.newChart(Chart.DEFAULT_QUALITY, toolkit); + } + + public static Chart chart(Quality quality, Toolkit toolkit) { + Chart2dComponentFactory f = new Chart2dComponentFactory(); + return f.newChart(quality, toolkit); + } + + public static Chart chart(Quality quality, String toolkit) { + Chart2dComponentFactory f = new Chart2dComponentFactory(); + return f.newChart(quality, toolkit); + } + + @Override + public Chart newChart(IChartComponentFactory factory, Quality quality, String toolkit){ + return new Chart2d(factory, quality, toolkit); + } + +} diff --git a/jzy3d-api/src/api/org/jzy3d/chart2d/View2d.java b/jzy3d-api/src/api/org/jzy3d/chart2d/View2d.java new file mode 100644 index 00000000..1de8dda6 --- /dev/null +++ b/jzy3d-api/src/api/org/jzy3d/chart2d/View2d.java @@ -0,0 +1,18 @@ +package org.jzy3d.chart2d; + +import org.jzy3d.chart.factories.IChartComponentFactory; +import org.jzy3d.maths.Coord3d; +import org.jzy3d.plot3d.rendering.canvas.ICanvas; +import org.jzy3d.plot3d.rendering.canvas.Quality; +import org.jzy3d.plot3d.rendering.scene.Scene; +import org.jzy3d.plot3d.rendering.view.AWTView; + +public class View2d extends AWTView { + public View2d(IChartComponentFactory factory, Scene scene, ICanvas canvas, Quality quality) { + super(factory, scene, canvas, quality); + } + + public Coord3d computeSceneScaling() { + return squarify(); + } +} diff --git a/jzy3d-api/src/api/org/jzy3d/chart2d/primitives/LineSerie2d.java b/jzy3d-api/src/api/org/jzy3d/chart2d/primitives/LineSerie2d.java new file mode 100644 index 00000000..d3fb7a4e --- /dev/null +++ b/jzy3d-api/src/api/org/jzy3d/chart2d/primitives/LineSerie2d.java @@ -0,0 +1,63 @@ +package org.jzy3d.chart2d.primitives; + +import java.util.List; + +import org.jzy3d.colors.Color; +import org.jzy3d.maths.Coord2d; +import org.jzy3d.maths.Coord3d; +import org.jzy3d.plot3d.primitives.AbstractDrawable; +import org.jzy3d.plot3d.primitives.Point; +import org.jzy3d.plot3d.primitives.SynchronizedLineStrip; + +public class LineSerie2d implements Serie2d { + protected SynchronizedLineStrip line = new SynchronizedLineStrip(); + + protected String name; + + public LineSerie2d(String name){ + this.name = name; + } + + @Override + public void add(float x, float y) { + line.add(new Point(new Coord3d(x, y, 0))); + } + + @Override + public void add(double x, double y) { + line.add(new Point(new Coord3d(x, y, 0))); + } + + @Override + public void add(Coord2d c) { + line.add(new Point(new Coord3d(c.x, c.y, 0))); + } + + @Override + public void add(List c) { + for(Coord2d c2: c){ + line.add(new Point(new Coord3d(c2.x, c2.y, 0))); + } + } + + @Override + public void setColor(Color color){ + line.setWireframeColor(color); + } + + @Override + public Color getColor(){ + return line.getWireframeColor(); + } + + @Override + public String getName() { + return name; + } + + @Override + public SynchronizedLineStrip getDrawable() { + return line; + } +} + diff --git a/jzy3d-api/src/api/org/jzy3d/chart2d/primitives/Serie2d.java b/jzy3d-api/src/api/org/jzy3d/chart2d/primitives/Serie2d.java new file mode 100644 index 00000000..7e427cea --- /dev/null +++ b/jzy3d-api/src/api/org/jzy3d/chart2d/primitives/Serie2d.java @@ -0,0 +1,20 @@ +package org.jzy3d.chart2d.primitives; + +import java.util.List; + +import org.jzy3d.colors.Color; +import org.jzy3d.maths.Coord2d; +import org.jzy3d.plot3d.primitives.AbstractDrawable; + +public interface Serie2d { + public void add(float x, float y); + public void add(double x, double y); + public void add(Coord2d c); + public void add(List c); + public String getName(); + + public void setColor(Color color); + public Color getColor(); + + public AbstractDrawable getDrawable(); +} diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/SynchronizedLineStrip.java b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/SynchronizedLineStrip.java new file mode 100644 index 00000000..402c52e8 --- /dev/null +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/SynchronizedLineStrip.java @@ -0,0 +1,132 @@ +package org.jzy3d.plot3d.primitives; + +import java.util.List; + +import javax.media.opengl.GL; + +import org.jzy3d.maths.Coord3d; +import org.jzy3d.plot3d.rendering.compat.GLES2CompatUtils; +import org.jzy3d.plot3d.transform.Transform; + +public class SynchronizedLineStrip extends LineStrip { + + public SynchronizedLineStrip() { + super(100); + } + + public SynchronizedLineStrip(int n) { + super(n); + } + + public SynchronizedLineStrip(List coords) { + super(coords); + } + + public SynchronizedLineStrip(Point c1, Point c2) { + super(c1, c2); + } + + public void drawLine(GL gl) { + gl.glLineWidth(width); + // gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); + // gl.glPolygonOffset(1.0f, 1.0f); + if (gl.isGL2()) { + gl.getGL2().glBegin(GL.GL_LINE_STRIP); + + synchronized (points) { + if (wfcolor == null) { + for (Point p : points) { + gl.getGL2().glColor4f(p.rgb.r, p.rgb.g, p.rgb.b, p.rgb.a); + gl.getGL2().glVertex3f(p.xyz.x, p.xyz.y, p.xyz.z); + } + } else { + for (Point p : points) { + gl.getGL2().glColor4f(wfcolor.r, wfcolor.g, wfcolor.b, wfcolor.a); + gl.getGL2().glVertex3f(p.xyz.x, p.xyz.y, p.xyz.z); + } + } + } + gl.getGL2().glEnd(); + } else { + GLES2CompatUtils.glBegin(GL.GL_LINE_STRIP); + + synchronized (points) { + + if (wfcolor == null) { + for (Point p : points) { + GLES2CompatUtils.glColor4f(p.rgb.r, p.rgb.g, p.rgb.b, p.rgb.a); + GLES2CompatUtils.glVertex3f(p.xyz.x, p.xyz.y, p.xyz.z); + } + } else { + for (Point p : points) { + GLES2CompatUtils.glColor4f(wfcolor.r, wfcolor.g, wfcolor.b, wfcolor.a); + GLES2CompatUtils.glVertex3f(p.xyz.x, p.xyz.y, p.xyz.z); + } + } + } + GLES2CompatUtils.glEnd(); + } + } + + public void drawPoints(GL gl) { + if (showPoints) { + if (gl.isGL2()) { + gl.getGL2().glBegin(GL.GL_POINTS); + synchronized (points) { + + for (Point p : points) { + if (wfcolor == null) + gl.getGL2().glColor4f(p.rgb.r, p.rgb.g, p.rgb.b, p.rgb.a); + else + gl.getGL2().glColor4f(wfcolor.r, wfcolor.g, wfcolor.b, wfcolor.a); + gl.getGL2().glVertex3f(p.xyz.x, p.xyz.y, p.xyz.z); + } + } + + gl.getGL2().glEnd(); + } else { + GLES2CompatUtils.glBegin(GL.GL_POINTS); + + synchronized (points) { + + for (Point p : points) { + if (wfcolor == null) + GLES2CompatUtils.glColor4f(p.rgb.r, p.rgb.g, p.rgb.b, p.rgb.a); + else + GLES2CompatUtils.glColor4f(wfcolor.r, wfcolor.g, wfcolor.b, wfcolor.a); + GLES2CompatUtils.glVertex3f(p.xyz.x, p.xyz.y, p.xyz.z); + } + } + GLES2CompatUtils.glEnd(); + } + } + } + + /* */ + + public void applyGeometryTransform(Transform transform) { + synchronized (points) { + + for (Point p : points) { + p.xyz = transform.compute(p.xyz); + } + } + updateBounds(); + } + + public void updateBounds() { + bbox.reset(); + synchronized (points) { + + for (Point p : points) + bbox.add(p); + } + } + + public void add(Point point) { + synchronized (points) { + points.add(point); + } + bbox.add(point); + } +} diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/AxeBox.java b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/AxeBox.java index 1eebe25d..0a33f3cc 100644 --- a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/AxeBox.java +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/AxeBox.java @@ -39,74 +39,6 @@ public class AxeBox implements IAxe { init(); } - protected void init() { - setScale(new Coord3d(1.0f, 1.0f, 1.0f)); - } - - public void dispose() { - } - - public ITextRenderer getTextRenderer() { - return txt; - } - - public void setTextRenderer(ITextRenderer renderer) { - txt = renderer; - } - - public View getView() { - return view; - } - - /** - * When setting a current view, the AxeBox can know the view is on mode - * CameraMode.TOP, and optimize some axis placement. - */ - public void setView(View view) { - this.view = view; - } - - /***********************************************************/ - - @Override - public void setAxe(BoundingBox3d bbox) { - this.boxBounds = bbox; - setAxeBox(bbox.getXmin(), bbox.getXmax(), bbox.getYmin(), bbox.getYmax(), bbox.getZmin(), bbox.getZmax()); - } - - @Override - public BoundingBox3d getBoxBounds() { - return boxBounds; - } - - @Override - public IAxeLayout getLayout() { - return layout; - } - - /** - * Return the boundingBox of this axis, including the volume occupied by the - * texts. This requires calling {@link draw()} before, which computes actual - * ticks position in 3d, and updates the bounds. - */ - public BoundingBox3d getWholeBounds() { - return wholeBounds; - } - - public Coord3d getCenter() { - return center; - } - - /** - * Set the scaling factor that are applyed on this object before GL2 - * commands. - */ - public void setScale(Coord3d scale) { - this.scale = scale; - } - - /***********************************************************/ - /** * Draws the AxeBox. The camera is used to determine which axis is closest * to the ur point ov view, in order to decide for an axis on which to @@ -114,7 +46,23 @@ public class AxeBox implements IAxe { */ @Override public void draw(GL gl, GLU glu, Camera camera) { - // Set scaling + cullingEnable(gl); + updateHiddenQuads(gl, camera); + + doTransform(gl); + drawFace(gl); + + doTransform(gl); + drawGrid(gl); + + doTransform(gl); + drawTicksAndLabels(gl, glu, camera); + + cullingDisable(gl); + } + + /** reset to identity and apply scaling */ + public void doTransform(GL gl) { if (gl.isGL2()) { gl.getGL2().glLoadIdentity(); gl.getGL2().glScalef(scale.x, scale.y, scale.z); @@ -122,16 +70,23 @@ public class AxeBox implements IAxe { GLES2CompatUtils.glLoadIdentity(); GLES2CompatUtils.glScalef(scale.x, scale.y, scale.z); } + } - // Set culling + public void cullingDisable(GL gl) { + gl.glDisable(GL2.GL_CULL_FACE); + } + + public void cullingEnable(GL gl) { gl.glEnable(GL2.GL_CULL_FACE); gl.glFrontFace(GL2.GL_CCW); gl.glCullFace(GL2.GL_FRONT); + } - // Draw cube in feedback buffer for computing hidden quads - quadIsHidden = getHiddenQuads(gl, camera); + /* */ - // Plain part of quad making the surrounding box + /* DRAW AXEBOX ELEMENTS */ + + public void drawFace(GL gl) { if (layout.isFaceDisplayed()) { Color quadcolor = layout.getQuadColor(); if (gl.isGL2()) { @@ -147,8 +102,9 @@ public class AxeBox implements IAxe { drawCube(gl, GL2.GL_RENDER); gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL); } + } - // Edge part of quads making the surrounding box + public void drawGrid(GL gl) { Color gridcolor = layout.getGridColor(); if (gl.isGL2()) { @@ -180,26 +136,23 @@ public class AxeBox implements IAxe { if (!quadIsHidden[quad]) drawGridOnQuad(gl, quad); gl.glDisable(GL2.GL_LINE_STIPPLE); + } - // Draw ticks on the closest axes + public void drawTicksAndLabels(GL gl, GLU glu, Camera camera) { wholeBounds.reset(); wholeBounds.add(boxBounds); - // gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + drawTicksAndLabelsX(gl, glu, camera); + drawTicksAndLabelsY(gl, glu, camera); + drawTicksAndLabelsZ(gl, glu, camera); + } - // Display x axis ticks + public void drawTicksAndLabelsX(GL gl, GLU glu, Camera camera) { if (xrange > 0 && layout.isXTickLabelDisplayed()) { // If we are on top, we make direct axe placement if (view != null && view.getViewMode().equals(ViewPositionMode.TOP)) { - BoundingBox3d bbox = drawTicks(gl, glu, camera, 1, AXE_X, layout.getXTickColor(), Halign.LEFT, Valign.TOP); // setup - // tick - // labels - // for - // X - // on - // the - // bottom + BoundingBox3d bbox = drawTicks(gl, glu, camera, 1, AXE_X, layout.getXTickColor(), Halign.LEFT, Valign.TOP); wholeBounds.add(bbox); } // otherwise computed placement @@ -218,18 +171,12 @@ public class AxeBox implements IAxe { } } } + } - // Display y axis ticks + public void drawTicksAndLabelsY(GL gl, GLU glu, Camera camera) { if (yrange > 0 && layout.isYTickLabelDisplayed()) { if (view != null && view.getViewMode().equals(ViewPositionMode.TOP)) { - BoundingBox3d bbox = drawTicks(gl, glu, camera, 2, AXE_Y, layout.getYTickColor(), Halign.LEFT, Valign.GROUND); // setup - // tick - // labels - // for - // Y - // on - // the - // left + BoundingBox3d bbox = drawTicks(gl, glu, camera, 2, AXE_Y, layout.getYTickColor(), Halign.LEFT, Valign.GROUND); wholeBounds.add(bbox); } else { int yselect = findClosestYaxe(camera); @@ -246,8 +193,9 @@ public class AxeBox implements IAxe { } } } + } - // Display z axis ticks + public void drawTicksAndLabelsZ(GL gl, GLU glu, Camera camera) { if (zrange > 0 && layout.isZTickLabelDisplayed()) { if (view != null && view.getViewMode().equals(ViewPositionMode.TOP)) { @@ -259,12 +207,445 @@ public class AxeBox implements IAxe { } } } - - // Unset culling - gl.glDisable(GL2.GL_CULL_FACE); } - /***********************************************************/ + /** + * Make all GL2 calls allowing to build a cube with 6 separate quads. Each + * quad is indexed from 0.0f to 5.0f using glPassThrough, and may be traced + * in feedback mode when mode=GL2.GL_FEEDBACK + */ + protected void drawCube(GL gl, int mode) { + for (int q = 0; q < 6; q++) { + if (gl.isGL2()) { + if (mode == GL2.GL_FEEDBACK) + gl.getGL2().glPassThrough((float) q); + gl.getGL2().glBegin(GL2.GL_QUADS); + for (int v = 0; v < 4; v++) { + gl.getGL2().glVertex3f(quadx[q][v], quady[q][v], quadz[q][v]); + } + gl.getGL2().glEnd(); + } else { + if (mode == GL2.GL_FEEDBACK) + GLES2CompatUtils.glPassThrough((float) q); + GLES2CompatUtils.glBegin(GL2.GL_QUADS); + for (int v = 0; v < 4; v++) { + GLES2CompatUtils.glVertex3f(quadx[q][v], quady[q][v], quadz[q][v]); + } + GLES2CompatUtils.glEnd(); + } + + } + } + + /** + * Draw a grid on the desired quad. + */ + protected void drawGridOnQuad(GL gl, int quad) { + // Draw X grid along X axis + if ((quad != 0) && (quad != 1)) { + double[] xticks = layout.getXTicks(); + for (int t = 0; t < xticks.length; t++) { + if (gl.isGL2()) { + gl.getGL2().glBegin(GL2.GL_LINES); + gl.getGL2().glVertex3d(xticks[t], quady[quad][0], quadz[quad][0]); + gl.getGL2().glVertex3d(xticks[t], quady[quad][2], quadz[quad][2]); + gl.getGL2().glEnd(); + } else { + // FIXME TO BE REWRITTEN ANDROID + } + } + } + // Draw Y grid along Y axis + if ((quad != 2) && (quad != 3)) { + double[] yticks = layout.getYTicks(); + for (int t = 0; t < yticks.length; t++) { + if (gl.isGL2()) { + gl.getGL2().glBegin(GL2.GL_LINES); + gl.getGL2().glVertex3d(quadx[quad][0], yticks[t], quadz[quad][0]); + gl.getGL2().glVertex3d(quadx[quad][2], yticks[t], quadz[quad][2]); + gl.getGL2().glEnd(); + } else { + // FIXME TO BE REWRITTEN ANDROID + } + } + } + // Draw Z grid along Z axis + if ((quad != 4) && (quad != 5)) { + double[] zticks = layout.getZTicks(); + for (int t = 0; t < zticks.length; t++) { + if (gl.isGL2()) { + gl.getGL2().glBegin(GL2.GL_LINES); + gl.getGL2().glVertex3d(quadx[quad][0], quady[quad][0], zticks[t]); + gl.getGL2().glVertex3d(quadx[quad][2], quady[quad][2], zticks[t]); + gl.getGL2().glEnd(); + } else { + // FIXME TO BE REWRITTEN ANDROID + } + } + } + } + + protected BoundingBox3d drawTicks(GL gl, GLU glu, Camera cam, int axis, int direction, Color color) { + return drawTicks(gl, glu, cam, axis, direction, color, null, null); + } + + /** Draws axis labels, tick lines and tick label */ + protected BoundingBox3d drawTicks(GL gl, GLU glu, Camera cam, int axis, int direction, Color color, Halign hal, Valign val) { + int quad_0; + int quad_1; + float tickLength = 20.0f; // with respect to range + float axeLabelDist = 2.5f; + BoundingBox3d ticksTxtBounds = new BoundingBox3d(); + + // Retrieve the quads that intersect and create the selected axe + if (direction == AXE_X) { + quad_0 = axeXquads[axis][0]; + quad_1 = axeXquads[axis][1]; + } else if (direction == AXE_Y) { + quad_0 = axeYquads[axis][0]; + quad_1 = axeYquads[axis][1]; + } else { // (axis==AXE_Z) + quad_0 = axeZquads[axis][0]; + quad_1 = axeZquads[axis][1]; + } + + // Computes POSition of ticks lying on the selected axe + // (i.e. 1st point of the tick line) + double xpos = normx[quad_0] + normx[quad_1]; + double ypos = normy[quad_0] + normy[quad_1]; + double zpos = normz[quad_0] + normz[quad_1]; + + // Computes the DIRection of the ticks + // assuming initial vector point is the center + float xdir = (normx[quad_0] + normx[quad_1]) - center.x; + float ydir = (normy[quad_0] + normy[quad_1]) - center.y; + float zdir = (normz[quad_0] + normz[quad_1]) - center.z; + xdir = xdir == 0 ? 0 : xdir / Math.abs(xdir); // so that direction as + // length 1 + ydir = ydir == 0 ? 0 : ydir / Math.abs(ydir); + zdir = zdir == 0 ? 0 : zdir / Math.abs(zdir); + + // Variables for storing the position of the LABel position + // (2nd point on the tick line) + double xlab; + double ylab; + double zlab; + + // Draw the label for axis + String axeLabel; + int dist = 1; + if (direction == AXE_X) { + xlab = center.x; + ylab = axeLabelDist * (yrange / tickLength) * dist * ydir + ypos; + zlab = axeLabelDist * (zrange / tickLength) * dist * zdir + zpos; + axeLabel = layout.getXAxeLabel(); + } else if (direction == AXE_Y) { + xlab = axeLabelDist * (xrange / tickLength) * dist * xdir + xpos; + ylab = center.y; + zlab = axeLabelDist * (zrange / tickLength) * dist * zdir + zpos; + axeLabel = layout.getYAxeLabel(); + } else { + xlab = axeLabelDist * (xrange / tickLength) * dist * xdir + xpos; + ylab = axeLabelDist * (yrange / tickLength) * dist * ydir + ypos; + zlab = center.z; + axeLabel = layout.getZAxeLabel(); + } + + if ((direction == AXE_X && layout.isXAxeLabelDisplayed()) || (direction == AXE_Y && layout.isYAxeLabelDisplayed()) || (direction == AXE_Z && layout.isZAxeLabelDisplayed())) { + Coord3d labelPosition = new Coord3d(xlab, ylab, zlab); + BoundingBox3d labelBounds = txt.drawText(gl, glu, cam, axeLabel, labelPosition, Halign.CENTER, Valign.CENTER, color); + if (labelBounds != null) + ticksTxtBounds.add(labelBounds); + } + + // Retrieve the selected tick positions + double ticks[]; + if (direction == AXE_X) + ticks = layout.getXTicks(); + else if (direction == AXE_Y) + ticks = layout.getYTicks(); + else + // (axis==AXE_Z) + ticks = layout.getZTicks(); + + // Draw the ticks, labels, and dotted lines iteratively + drawAxisTicks(gl, glu, cam, direction, color, hal, val, tickLength, ticksTxtBounds, xpos, ypos, zpos, xdir, ydir, zdir, ticks); + return ticksTxtBounds; + } + + public void drawAxisTicks(GL gl, GLU glu, Camera cam, int direction, Color color, Halign hal, Valign val, float tickLength, BoundingBox3d ticksTxtBounds, double xpos, + double ypos, double zpos, float xdir, float ydir, float zdir, double[] ticks) { + Halign hAlign; + Valign vAlign; + double xlab; + double ylab; + double zlab; + String tickLabel = ""; + + for (int t = 0; t < ticks.length; t++) { + // Shift the tick vector along the selected axis + // and set the tick length + if (direction == AXE_X) { + xpos = ticks[t]; + xlab = xpos; + ylab = (yrange / tickLength) * ydir + ypos; + zlab = (zrange / tickLength) * zdir + zpos; + tickLabel = layout.getXTickRenderer().format(xpos); + } else if (direction == AXE_Y) { + ypos = ticks[t]; + xlab = (xrange / tickLength) * xdir + xpos; + ylab = ypos; + zlab = (zrange / tickLength) * zdir + zpos; + tickLabel = layout.getYTickRenderer().format(ypos); + } else { // (axis==AXE_Z) + zpos = ticks[t]; + xlab = (xrange / tickLength) * xdir + xpos; + ylab = (yrange / tickLength) * ydir + ypos; + zlab = zpos; + tickLabel = layout.getZTickRenderer().format(zpos); + } + Coord3d tickPosition = new Coord3d(xlab, ylab, zlab); + + if (layout.isTickLineDisplayed()) { + if (gl.isGL2()) { + drawTickLine(gl, color, xpos, ypos, zpos, xlab, ylab, zlab); + } else { + // FIXME REWRITE ANDROID + } + } + + // Select the alignement of the tick label + hAlign = layoutHorizontal(cam, hal, tickPosition); + vAlign = layoutVertical(direction, val, zdir); + + // Draw the text label of the current tick + drawTickNumericLabel(gl, glu, cam, color, hAlign, vAlign, ticksTxtBounds, tickLabel, tickPosition); + } + } + + public void drawTickNumericLabel(GL gl, GLU glu, Camera cam, Color color, Halign hAlign, Valign vAlign, BoundingBox3d ticksTxtBounds, String tickLabel, Coord3d tickPosition) { + //doTransform(gl); + if (gl.isGL2()) { + gl.getGL2().glLoadIdentity(); + gl.getGL2().glScalef(scale.x, scale.y, scale.z); + //gl.getGL2().glRotatef(90, 1, 0, 1); + } else { + GLES2CompatUtils.glLoadIdentity(); + //GLES2CompatUtils.glRotatef((float)Math.PI/2, 1, 0, 1); + GLES2CompatUtils.glScalef(scale.x, scale.y, scale.z); + } + + + BoundingBox3d tickBounds = txt.drawText(gl, glu, cam, tickLabel, tickPosition, hAlign, vAlign, color); + if (tickBounds != null) + ticksTxtBounds.add(tickBounds); + } + + public Valign layoutVertical(int direction, Valign val, float zdir) { + Valign vAlign; + if (val == null) { + if (direction == AXE_Z) + vAlign = Valign.CENTER; + else { + if (zdir > 0) + vAlign = Valign.TOP; + else + vAlign = Valign.BOTTOM; + } + } else + vAlign = val; + return vAlign; + } + + public Halign layoutHorizontal(Camera cam, Halign hal, Coord3d tickPosition) { + Halign hAlign; + if (hal == null) + hAlign = cam.side(tickPosition) ? Halign.LEFT : Halign.RIGHT; + else + hAlign = hal; + return hAlign; + } + + public void drawTickLine(GL gl, Color color, double xpos, double ypos, double zpos, double xlab, double ylab, double zlab) { + gl.getGL2().glColor3f(color.r, color.g, color.b); + gl.getGL2().glLineWidth(1); + + // Draw the tick line + gl.getGL2().glBegin(GL2.GL_LINES); + gl.getGL2().glVertex3d(xpos, ypos, zpos); + gl.getGL2().glVertex3d(xlab, ylab, zlab); + gl.getGL2().glEnd(); + } + + /* */ + + /* AXIS SELECTION */ + + /** + * Selects the closest displayable X axe from camera + */ + protected int findClosestXaxe(Camera cam) { + int na = 4; + double[] distAxeX = new double[na]; + + // keeps axes that are not at intersection of 2 quads + for (int a = 0; a < na; a++) { + if (quadIsHidden[axeXquads[a][0]] ^ quadIsHidden[axeXquads[a][1]]) + distAxeX[a] = new Vector3d(axeXx[a][0], axeXy[a][0], axeXz[a][0], axeXx[a][1], axeXy[a][1], axeXz[a][1]).distance(cam.getEye()); + else + distAxeX[a] = Double.MAX_VALUE; + } + + // prefers the lower one + for (int a = 0; a < na; a++) { + if (distAxeX[a] < Double.MAX_VALUE) { + if (center.z > (axeXz[a][0] + axeXz[a][1]) / 2) + distAxeX[a] *= -1; + } + } + + return min(distAxeX); + } + + /** + * Selects the closest displayable Y axe from camera + */ + protected int findClosestYaxe(Camera cam) { + int na = 4; + double[] distAxeY = new double[na]; + + // keeps axes that are not at intersection of 2 quads + for (int a = 0; a < na; a++) { + if (quadIsHidden[axeYquads[a][0]] ^ quadIsHidden[axeYquads[a][1]]) + distAxeY[a] = new Vector3d(axeYx[a][0], axeYy[a][0], axeYz[a][0], axeYx[a][1], axeYy[a][1], axeYz[a][1]).distance(cam.getEye()); + else + distAxeY[a] = Double.MAX_VALUE; + } + + // prefers the lower one + for (int a = 0; a < na; a++) { + if (distAxeY[a] < Double.MAX_VALUE) { + if (center.z > (axeYz[a][0] + axeYz[a][1]) / 2) + distAxeY[a] *= -1; + } + } + + return min(distAxeY); + } + + /** + * Selects the closest displayable Z axe from camera + */ + protected int findClosestZaxe(Camera cam) { + int na = 4; + double[] distAxeZ = new double[na]; + + // keeps axes that are not at intersection of 2 quads + for (int a = 0; a < na; a++) { + if (quadIsHidden[axeZquads[a][0]] ^ quadIsHidden[axeZquads[a][1]]) + distAxeZ[a] = new Vector3d(axeZx[a][0], axeZy[a][0], axeZz[a][0], axeZx[a][1], axeZy[a][1], axeZz[a][1]).distance(cam.getEye()); + else + distAxeZ[a] = Double.MAX_VALUE; + } + + // prefers the right one + for (int a = 0; a < na; a++) { + if (distAxeZ[a] < Double.MAX_VALUE) { + Coord3d axeCenter = new Coord3d((axeZx[a][0] + axeZx[a][1]) / 2, (axeZy[a][0] + axeZy[a][1]) / 2, (axeZz[a][0] + axeZz[a][1]) / 2); + if (!cam.side(axeCenter)) + distAxeZ[a] *= -1; + } + } + + return min(distAxeZ); + } + + /** + * Return the index of the minimum value contained in the input array of + * doubles. If no value is smaller than Double.MAX_VALUE, the returned index + * is -1. + */ + protected int min(double[] values) { + double minv = Double.MAX_VALUE; + int index = -1; + + for (int i = 0; i < values.length; i++) + if (values[i] < minv) { + minv = values[i]; + index = i; + } + return index; + } + + /* */ + + /* COMPUTATION OF HIDDEN QUADS */ + + public void updateHiddenQuads(GL gl, Camera camera) { + quadIsHidden = getHiddenQuads(gl, camera); + } + + /** Computes the visibility of each cube face. */ + protected boolean[] getHiddenQuads(GL gl, Camera cam) { + boolean[] status = new boolean[6]; + + Coord3d se = cam.getEye().div(scale); + + if (se.x <= center.x) { + status[0] = false; + status[1] = true; + } else { + status[0] = true; + status[1] = false; + } + if (se.y <= center.y) { + status[2] = false; + status[3] = true; + } else { + status[2] = true; + status[3] = false; + } + if (se.z <= center.z) { + status[4] = false; + status[5] = true; + } else { + status[4] = true; + status[5] = false; + } + return status; + } + + /* */ + + /** + * Print out parameters of a gl call in 3dColor mode. + */ + protected int print3DcolorVertex(int size, int count, float[] buffer) { + int i; + int id = size - count; + int veclength = 7; + + System.out.print(" [" + id + "]"); + for (i = 0; i < veclength; i++) { + System.out.print(" " + buffer[size - count]); + count = count - 1; + } + System.out.println(); + return count; + } + + /** + * Print out display status of quads. + */ + protected void printHiddenQuads() { + for (int t = 0; t < quadIsHidden.length; t++) + if (quadIsHidden[t]) + System.out.println("Quad[" + t + "] is not displayed"); + else + System.out.println("Quad[" + t + "] is displayed"); + } + + /* */ /** * Set the parameters and data of the AxeBox. @@ -551,411 +932,80 @@ public class AxeBox implements IAxe { */ } - /******************************************************************/ - /** DRAW AXEBOX ELEMENTS **/ + protected void init() { + setScale(new Coord3d(1.0f, 1.0f, 1.0f)); + } - /** - * Make all GL2 calls allowing to build a cube with 6 separate quads. Each - * quad is indexed from 0.0f to 5.0f using glPassThrough, and may be traced - * in feedback mode when mode=GL2.GL_FEEDBACK - */ - protected void drawCube(GL gl, int mode) { - for (int q = 0; q < 6; q++) { - if (gl.isGL2()) { - if (mode == GL2.GL_FEEDBACK) - gl.getGL2().glPassThrough((float) q); - gl.getGL2().glBegin(GL2.GL_QUADS); - for (int v = 0; v < 4; v++) { - gl.getGL2().glVertex3f(quadx[q][v], quady[q][v], quadz[q][v]); - } - gl.getGL2().glEnd(); - } else { - if (mode == GL2.GL_FEEDBACK) - GLES2CompatUtils.glPassThrough((float) q); - GLES2CompatUtils.glBegin(GL2.GL_QUADS); - for (int v = 0; v < 4; v++) { - GLES2CompatUtils.glVertex3f(quadx[q][v], quady[q][v], quadz[q][v]); - } - GLES2CompatUtils.glEnd(); - } + public void dispose() { + } - } + public ITextRenderer getTextRenderer() { + return txt; + } + + public void setTextRenderer(ITextRenderer renderer) { + txt = renderer; + } + + public View getView() { + return view; + } + + @Override + public BoundingBox3d getBoxBounds() { + return boxBounds; + } + + @Override + public IAxeLayout getLayout() { + return layout; } /** - * Draw a grid on the desired quad. + * When setting a current view, the AxeBox can know the view is on mode + * CameraMode.TOP, and optimize some axis placement. */ - protected void drawGridOnQuad(GL gl, int quad) { - // Draw X grid along X axis - if ((quad != 0) && (quad != 1)) { - double[] xticks = layout.getXTicks(); - for (int t = 0; t < xticks.length; t++) { - if (gl.isGL2()) { - gl.getGL2().glBegin(GL2.GL_LINES); - gl.getGL2().glVertex3d(xticks[t], quady[quad][0], quadz[quad][0]); - gl.getGL2().glVertex3d(xticks[t], quady[quad][2], quadz[quad][2]); - gl.getGL2().glEnd(); - } else { - // FIXME TO BE REWRITTEN ANDROID - } - } - } - // Draw Y grid along Y axis - if ((quad != 2) && (quad != 3)) { - double[] yticks = layout.getYTicks(); - for (int t = 0; t < yticks.length; t++) { - if (gl.isGL2()) { - gl.getGL2().glBegin(GL2.GL_LINES); - gl.getGL2().glVertex3d(quadx[quad][0], yticks[t], quadz[quad][0]); - gl.getGL2().glVertex3d(quadx[quad][2], yticks[t], quadz[quad][2]); - gl.getGL2().glEnd(); - } else { - // FIXME TO BE REWRITTEN ANDROID - } - } - } - // Draw Z grid along Z axis - if ((quad != 4) && (quad != 5)) { - double[] zticks = layout.getZTicks(); - for (int t = 0; t < zticks.length; t++) { - if (gl.isGL2()) { - gl.getGL2().glBegin(GL2.GL_LINES); - gl.getGL2().glVertex3d(quadx[quad][0], quady[quad][0], zticks[t]); - gl.getGL2().glVertex3d(quadx[quad][2], quady[quad][2], zticks[t]); - gl.getGL2().glEnd(); - } else { - // FIXME TO BE REWRITTEN ANDROID - } - } - } + public void setView(View view) { + this.view = view; } - /* - * Draws ticks on the given direction, by using the desired axe. - */ - protected BoundingBox3d drawTicks(GL gl, GLU glu, Camera cam, int axis, int direction, Color color) { - return drawTicks(gl, glu, cam, axis, direction, color, null, null); - } - - protected BoundingBox3d drawTicks(GL gl, GLU glu, Camera cam, int axis, int direction, Color color, Halign hal, Valign val) { - int quad_0; - int quad_1; - Halign hAlign; - Valign vAlign; - float tickLength = 20.0f; // with respect to range - float axeLabelDist = 2.5f; - BoundingBox3d ticksTxtBounds = new BoundingBox3d(); - - // Retrieve the quads that intersect and create the selected axe - if (direction == AXE_X) { - quad_0 = axeXquads[axis][0]; - quad_1 = axeXquads[axis][1]; - } else if (direction == AXE_Y) { - quad_0 = axeYquads[axis][0]; - quad_1 = axeYquads[axis][1]; - } else { // (axis==AXE_Z) - quad_0 = axeZquads[axis][0]; - quad_1 = axeZquads[axis][1]; - } - - // Computes POSition of ticks lying on the selected axe - // (i.e. 1st point of the tick line) - double xpos = normx[quad_0] + normx[quad_1]; - double ypos = normy[quad_0] + normy[quad_1]; - double zpos = normz[quad_0] + normz[quad_1]; - - // Variables for storing the position of the LABel position - // (2nd point on the tick line) - double xlab; - double ylab; - double zlab; - - // Computes the DIRection of the ticks - // assuming initial vector point is the center - float xdir = (normx[quad_0] + normx[quad_1]) - center.x; - float ydir = (normy[quad_0] + normy[quad_1]) - center.y; - float zdir = (normz[quad_0] + normz[quad_1]) - center.z; - xdir = xdir == 0 ? 0 : xdir / Math.abs(xdir); // so that direction as - // length 1 - ydir = ydir == 0 ? 0 : ydir / Math.abs(ydir); - zdir = zdir == 0 ? 0 : zdir / Math.abs(zdir); - - // Draw the label for axis - String axeLabel; - int dist = 1; - if (direction == AXE_X) { - xlab = center.x; - ylab = axeLabelDist * (yrange / tickLength) * dist * ydir + ypos; - zlab = axeLabelDist * (zrange / tickLength) * dist * zdir + zpos; - axeLabel = layout.getXAxeLabel(); - } else if (direction == AXE_Y) { - xlab = axeLabelDist * (xrange / tickLength) * dist * xdir + xpos; - ylab = center.y; - zlab = axeLabelDist * (zrange / tickLength) * dist * zdir + zpos; - axeLabel = layout.getYAxeLabel(); - } else { - xlab = axeLabelDist * (xrange / tickLength) * dist * xdir + xpos; - ylab = axeLabelDist * (yrange / tickLength) * dist * ydir + ypos; - zlab = center.z; - axeLabel = layout.getZAxeLabel(); - } - - if ((direction == AXE_X && layout.isXAxeLabelDisplayed()) || (direction == AXE_Y && layout.isYAxeLabelDisplayed()) || (direction == AXE_Z && layout.isZAxeLabelDisplayed())) { - Coord3d labelPosition = new Coord3d(xlab, ylab, zlab); - BoundingBox3d labelBounds = txt.drawText(gl, glu, cam, axeLabel, labelPosition, Halign.CENTER, Valign.CENTER, color); - if (labelBounds != null) - ticksTxtBounds.add(labelBounds); - } - - // Retrieve the selected tick positions - double ticks[]; - if (direction == AXE_X) - ticks = layout.getXTicks(); - else if (direction == AXE_Y) - ticks = layout.getYTicks(); - else - // (axis==AXE_Z) - ticks = layout.getZTicks(); - - // Draw the ticks, labels, and dotted lines iteratively - String tickLabel = ""; - - for (int t = 0; t < ticks.length; t++) { - // Shift the tick vector along the selected axis - // and set the tick length - if (direction == AXE_X) { - xpos = ticks[t]; - xlab = xpos; - ylab = (yrange / tickLength) * ydir + ypos; - zlab = (zrange / tickLength) * zdir + zpos; - tickLabel = layout.getXTickRenderer().format(xpos); - } else if (direction == AXE_Y) { - ypos = ticks[t]; - xlab = (xrange / tickLength) * xdir + xpos; - ylab = ypos; - zlab = (zrange / tickLength) * zdir + zpos; - tickLabel = layout.getYTickRenderer().format(ypos); - } else { // (axis==AXE_Z) - zpos = ticks[t]; - xlab = (xrange / tickLength) * xdir + xpos; - ylab = (yrange / tickLength) * ydir + ypos; - zlab = zpos; - tickLabel = layout.getZTickRenderer().format(zpos); - } - Coord3d tickPosition = new Coord3d(xlab, ylab, zlab); - - if (gl.isGL2()) { - gl.getGL2().glColor3f(color.r, color.g, color.b); - gl.getGL2().glLineWidth(1); - - // Draw the tick line - gl.getGL2().glBegin(GL2.GL_LINES); - gl.getGL2().glVertex3d(xpos, ypos, zpos); - gl.getGL2().glVertex3d(xlab, ylab, zlab); - gl.getGL2().glEnd(); - } else { - // FIXME REWRITE ANDROID - } - - // Select the alignement of the tick label - if (hal == null) - hAlign = cam.side(tickPosition) ? Halign.LEFT : Halign.RIGHT; - else - hAlign = hal; - - if (val == null) { - if (direction == AXE_Z) - vAlign = Valign.CENTER; - else { - if (zdir > 0) - vAlign = Valign.TOP; - else - vAlign = Valign.BOTTOM; - } - } else - vAlign = val; - - // Draw the text label of the current tick - BoundingBox3d tickBounds = txt.drawText(gl, glu, cam, tickLabel, tickPosition, hAlign, vAlign, color); - if (tickBounds != null) - ticksTxtBounds.add(tickBounds); - } - - return ticksTxtBounds; - } - - /******************************************************************/ - /** AXIS SELECTION **/ - - /** - * Selects the closest displayable X axe from camera - */ - protected int findClosestXaxe(Camera cam) { - int na = 4; - double[] distAxeX = new double[na]; - - // keeps axes that are not at intersection of 2 quads - for (int a = 0; a < na; a++) { - if (quadIsHidden[axeXquads[a][0]] ^ quadIsHidden[axeXquads[a][1]]) - distAxeX[a] = new Vector3d(axeXx[a][0], axeXy[a][0], axeXz[a][0], axeXx[a][1], axeXy[a][1], axeXz[a][1]).distance(cam.getEye()); - else - distAxeX[a] = Double.MAX_VALUE; - } - - // prefers the lower one - for (int a = 0; a < na; a++) { - if (distAxeX[a] < Double.MAX_VALUE) { - if (center.z > (axeXz[a][0] + axeXz[a][1]) / 2) - distAxeX[a] *= -1; - } - } - - return min(distAxeX); + @Override + public void setAxe(BoundingBox3d bbox) { + this.boxBounds = bbox; + setAxeBox(bbox.getXmin(), bbox.getXmax(), bbox.getYmin(), bbox.getYmax(), bbox.getZmin(), bbox.getZmax()); } /** - * Selects the closest displayable Y axe from camera + * Return the boundingBox of this axis, including the volume occupied by the + * texts. This requires calling {@link draw()} before, which computes actual + * ticks position in 3d, and updates the bounds. */ - protected int findClosestYaxe(Camera cam) { - int na = 4; - double[] distAxeY = new double[na]; + public BoundingBox3d getWholeBounds() { + return wholeBounds; + } - // keeps axes that are not at intersection of 2 quads - for (int a = 0; a < na; a++) { - if (quadIsHidden[axeYquads[a][0]] ^ quadIsHidden[axeYquads[a][1]]) - distAxeY[a] = new Vector3d(axeYx[a][0], axeYy[a][0], axeYz[a][0], axeYx[a][1], axeYy[a][1], axeYz[a][1]).distance(cam.getEye()); - else - distAxeY[a] = Double.MAX_VALUE; - } - - // prefers the lower one - for (int a = 0; a < na; a++) { - if (distAxeY[a] < Double.MAX_VALUE) { - if (center.z > (axeYz[a][0] + axeYz[a][1]) / 2) - distAxeY[a] *= -1; - } - } - - return min(distAxeY); + public Coord3d getCenter() { + return center; } /** - * Selects the closest displayable Z axe from camera + * Set the scaling factor that are applyed on this object before GL2 + * commands. */ - protected int findClosestZaxe(Camera cam) { - int na = 4; - double[] distAxeZ = new double[na]; - - // keeps axes that are not at intersection of 2 quads - for (int a = 0; a < na; a++) { - if (quadIsHidden[axeZquads[a][0]] ^ quadIsHidden[axeZquads[a][1]]) - distAxeZ[a] = new Vector3d(axeZx[a][0], axeZy[a][0], axeZz[a][0], axeZx[a][1], axeZy[a][1], axeZz[a][1]).distance(cam.getEye()); - else - distAxeZ[a] = Double.MAX_VALUE; - } - - // prefers the right one - for (int a = 0; a < na; a++) { - if (distAxeZ[a] < Double.MAX_VALUE) { - Coord3d axeCenter = new Coord3d((axeZx[a][0] + axeZx[a][1]) / 2, (axeZy[a][0] + axeZy[a][1]) / 2, (axeZz[a][0] + axeZz[a][1]) / 2); - if (!cam.side(axeCenter)) - distAxeZ[a] *= -1; - } - } - - return min(distAxeZ); + public void setScale(Coord3d scale) { + this.scale = scale; } - /** - * Return the index of the minimum value contained in the input array of - * doubles. If no value is smaller than Double.MAX_VALUE, the returned index - * is -1. - */ - protected int min(double[] values) { - double minv = Double.MAX_VALUE; - int index = -1; + /* */ - for (int i = 0; i < values.length; i++) - if (values[i] < minv) { - minv = values[i]; - index = i; - } - return index; - } - - /******************************************************************/ - /** COMPUTATION OF HIDDEN QUADS **/ - - /** Computes the visibility of each cube face. */ - protected boolean[] getHiddenQuads(GL gl, Camera cam) { - boolean[] status = new boolean[6]; - - Coord3d se = cam.getEye().div(scale); - - if (se.x <= center.x) { - status[0] = false; - status[1] = true; - } else { - status[0] = true; - status[1] = false; - } - if (se.y <= center.y) { - status[2] = false; - status[3] = true; - } else { - status[2] = true; - status[3] = false; - } - if (se.z <= center.z) { - status[4] = false; - status[5] = true; - } else { - status[4] = true; - status[5] = false; - } - return status; - } - - /******************************************************************/ - - /** - * Print out parameters of a gl call in 3dColor mode. - */ - protected int print3DcolorVertex(int size, int count, float[] buffer) { - int i; - int id = size - count; - int veclength = 7; - - System.out.print(" [" + id + "]"); - for (i = 0; i < veclength; i++) { - System.out.print(" " + buffer[size - count]); - count = count - 1; - } - System.out.println(); - return count; - } - - /** - * Print out display status of quads. - */ - protected void printHiddenQuads() { - for (int t = 0; t < quadIsHidden.length; t++) - if (quadIsHidden[t]) - System.out.println("Quad[" + t + "] is not displayed"); - else - System.out.println("Quad[" + t + "] is displayed"); - } - - /******************************************************************/ + /* */ protected static final int PRECISION = 6; protected View view; - protected ITextRenderer txt = new TextBitmapRenderer(); // use this text - // renderer to get - // occupied volume - // by text + // use this text renderer to get occupied volume by text + protected ITextRenderer txt = new TextBitmapRenderer(); protected IAxeLayout layout; diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/AxeBoxLayout.java b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/AxeBoxLayout.java index 539569fd..a4017243 100644 --- a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/AxeBoxLayout.java +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/AxeBoxLayout.java @@ -261,10 +261,22 @@ public class AxeBoxLayout implements IAxeLayout{ public void setZTickLabelDisplayed(boolean tickLabelDisplayed) { zTickLabelDisplayed = tickLabelDisplayed; } + + public boolean isTickLineDisplayed() { + return tickLineDisplayed; + } + + public void setTickLineDisplayed(boolean tickLineDisplayed) { + this.tickLineDisplayed = tickLineDisplayed; + } - /**********************************************************/ + + + /**********************************************************/ + + protected boolean tickLineDisplayed = true; protected String xAxeLabel; protected String yAxeLabel; diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/IAxeLayout.java b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/IAxeLayout.java index 6644aa7c..fbab3a12 100644 --- a/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/IAxeLayout.java +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/primitives/axes/layout/IAxeLayout.java @@ -41,6 +41,10 @@ public interface IAxeLayout { public boolean isYTickLabelDisplayed(); public boolean isZTickLabelDisplayed(); + public boolean isTickLineDisplayed(); + public void setTickLineDisplayed(boolean status); + + public void setXTickProvider(ITickProvider provider); public void setYTickProvider(ITickProvider provider); public void setZTickProvider(ITickProvider provider); @@ -72,4 +76,5 @@ public interface IAxeLayout { public Color getXTickColor(); public Color getYTickColor(); public Color getZTickColor(); + } diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/text/renderers/TextBitmapRenderer.java b/jzy3d-api/src/api/org/jzy3d/plot3d/text/renderers/TextBitmapRenderer.java index 099b73a7..90150980 100644 --- a/jzy3d-api/src/api/org/jzy3d/plot3d/text/renderers/TextBitmapRenderer.java +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/text/renderers/TextBitmapRenderer.java @@ -21,119 +21,111 @@ import com.jogamp.opengl.util.gl2.GLUT; * * @author Martin */ -public class TextBitmapRenderer extends AbstractTextRenderer implements - ITextRenderer { - /** - * The TextBitmap class provides support for drawing ASCII characters Any - * non ascii caracter will be replaced by a square. - */ - public TextBitmapRenderer() { - super(); - font = GLUT.BITMAP_HELVETICA_10; - fontHeight = 10; - } +public class TextBitmapRenderer extends AbstractTextRenderer implements ITextRenderer { + /** + * The TextBitmap class provides support for drawing ASCII characters Any + * non ascii caracter will be replaced by a square. + */ + public TextBitmapRenderer() { + super(); + font = GLUT.BITMAP_HELVETICA_10; + fontHeight = 10; + } - @Override - public void drawSimpleText(GL gl, GLU glu, Camera cam, String s, - Coord3d position, Color color) { - if (gl.isGL2()) { - gl.getGL2().glColor3f(color.r, color.g, color.b); - gl.getGL2().glRasterPos3f(position.x, position.y, position.z); - } else { - GLES2CompatUtils.glColor3f(color.r, color.g, color.b); - GLES2CompatUtils.glRasterPos3f(position.x, position.y, position.z); - } + @Override + public void drawSimpleText(GL gl, GLU glu, Camera cam, String s, Coord3d position, Color color) { + if (gl.isGL2()) { + gl.getGL2().glColor3f(color.r, color.g, color.b); + gl.getGL2().glRasterPos3f(position.x, position.y, position.z); + } else { + GLES2CompatUtils.glColor3f(color.r, color.g, color.b); + GLES2CompatUtils.glRasterPos3f(position.x, position.y, position.z); + } - glut.glutBitmapString(font, s); - } + glut.glutBitmapString(font, s); + } - /** - * Draw a string at the specified position and compute the 3d volume - * occupied by the string according to the current Camera configuration. - */ - @Override - public BoundingBox3d drawText(GL gl, GLU glu, Camera cam, String s, - Coord3d position, Halign halign, Valign valign, Color color, - Coord2d screenOffset, Coord3d sceneOffset) { - if (gl.isGL2()) { - gl.getGL2().glColor3f(color.r, color.g, color.b); - } else { - GLES2CompatUtils.glColor3f(color.r, color.g, color.b); - } + /** + * Draw a string at the specified position and compute the 3d volume + * occupied by the string according to the current Camera configuration. + */ + @Override + public BoundingBox3d drawText(GL gl, GLU glu, Camera cam, String text, Coord3d position, Halign halign, Valign valign, Color color, Coord2d screenOffset, Coord3d sceneOffset) { + if (gl.isGL2()) { + gl.getGL2().glColor3f(color.r, color.g, color.b); + } else { + GLES2CompatUtils.glColor3f(color.r, color.g, color.b); + } + if (cam == null) + return null; - if (cam == null) - return null; + Coord3d posScreen = cam.modelToScreen(gl, glu, position); - Coord3d posScreen = cam.modelToScreen(gl, glu, position); + // System.out.println(posScreen); - // System.out.println(posScreen); + // compute a corrected position according to layout + float strlen = glut.glutBitmapLength(font, text); + float x = 0.0f; + float y = 0.0f; - // compute a corrected position according to layout - float strlen = glut.glutBitmapLength(font, s); - float x = 0.0f; - float y = 0.0f; + if (halign == Halign.RIGHT) + x = posScreen.x; + else if (halign == Halign.CENTER) + x = posScreen.x - strlen / 2; + else if (halign == Halign.LEFT) + x = posScreen.x - strlen; - if (halign == Halign.RIGHT) - x = posScreen.x; - else if (halign == Halign.CENTER) - x = posScreen.x - strlen / 2; - else if (halign == Halign.LEFT) - x = posScreen.x - strlen; + if (valign == Valign.TOP) + y = posScreen.y; + else if (valign == Valign.GROUND) + y = posScreen.y; + else if (valign == Valign.CENTER) + y = posScreen.y - fontHeight / 2; + else if (valign == Valign.BOTTOM) + y = posScreen.y - fontHeight; - if (valign == Valign.TOP) - y = posScreen.y; - else if (valign == Valign.GROUND) - y = posScreen.y; - else if (valign == Valign.CENTER) - y = posScreen.y - fontHeight / 2; - else if (valign == Valign.BOTTOM) - y = posScreen.y - fontHeight; + Coord3d posScreenShifted = new Coord3d(x + screenOffset.x, y + screenOffset.y, posScreen.z); + Coord3d posReal; - Coord3d posScreenShifted = new Coord3d(x + screenOffset.x, y - + screenOffset.y, posScreen.z); - Coord3d posReal; + try { + posReal = cam.screenToModel(gl, glu, posScreenShifted); + } catch (RuntimeException e) { + // TODO: solve this bug due to a Camera.PERSPECTIVE mode. + System.err.println("TextBitmap.drawText(): could not process text position: " + posScreen + " " + posScreenShifted); + return new BoundingBox3d(); + } - try { - posReal = cam.screenToModel(gl, glu, posScreenShifted); - } catch (RuntimeException e) { // TODO: really solve this bug due to a - // Camera.PERSPECTIVE mode. - System.err - .println("TextBitmap.drawText(): could not process text position: " - + posScreen + " " + posScreenShifted); - return new BoundingBox3d(); - } + // Draws actual string + if (gl.isGL2()) { + gl.getGL2().glRasterPos3f(posReal.x + sceneOffset.x, posReal.y + sceneOffset.y, posReal.z + sceneOffset.z); + } else { + GLES2CompatUtils.glRasterPos3f(posReal.x + sceneOffset.x, posReal.y + sceneOffset.y, posReal.z + sceneOffset.z); + } - // Draws actual string - if (gl.isGL2()) { - gl.getGL2().glRasterPos3f(posReal.x + sceneOffset.x, posReal.y + sceneOffset.y, - posReal.z + sceneOffset.z); - } else { - GLES2CompatUtils.glRasterPos3f(posReal.x + sceneOffset.x, posReal.y + sceneOffset.y, - posReal.z + sceneOffset.z); - } - - glut.glutBitmapString(font, s); + //gl.getGL2().glRotatef(90, 0, 0, 1); + + glut.glutBitmapString(font, text); - // Compute bounds of text - Coord3d botLeft = new Coord3d(); - Coord3d topRight = new Coord3d(); - botLeft.x = posScreenShifted.x; - botLeft.y = posScreenShifted.y; - botLeft.z = posScreenShifted.z; - topRight.x = botLeft.x + strlen; - topRight.y = botLeft.y + fontHeight; - topRight.z = botLeft.z; + // Compute bounds of text + Coord3d botLeft = new Coord3d(); + Coord3d topRight = new Coord3d(); + botLeft.x = posScreenShifted.x; + botLeft.y = posScreenShifted.y; + botLeft.z = posScreenShifted.z; + topRight.x = botLeft.x + strlen; + topRight.y = botLeft.y + fontHeight; + topRight.z = botLeft.z; - BoundingBox3d txtBounds = new BoundingBox3d(); - txtBounds.add(cam.screenToModel(gl, glu, botLeft)); - txtBounds.add(cam.screenToModel(gl, glu, topRight)); - return txtBounds; - } + BoundingBox3d txtBounds = new BoundingBox3d(); + txtBounds.add(cam.screenToModel(gl, glu, botLeft)); + txtBounds.add(cam.screenToModel(gl, glu, topRight)); + return txtBounds; + } - /********************************************************************/ + /********************************************************************/ - protected static GLUT glut = new GLUT(); - protected int fontHeight; - protected int font; + protected static GLUT glut = new GLUT(); + protected int fontHeight; + protected int font; } diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/transform/Transform.java b/jzy3d-api/src/api/org/jzy3d/plot3d/transform/Transform.java index 62938c70..4ce87176 100644 --- a/jzy3d-api/src/api/org/jzy3d/plot3d/transform/Transform.java +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/transform/Transform.java @@ -43,7 +43,7 @@ public class Transform { sequence.add(next); } - /*******************************************************************/ + /* */ /** * Appends a Transformer to the sequence that this Transform must performs. @@ -64,7 +64,7 @@ public class Transform { sequence.add(next); } - /***********************************************************/ + /* */ /** * Load the identity matrix and executes the stored sequence of Transformer. diff --git a/jzy3d-api/src/api/org/jzy3d/plot3d/transform/TranslateDrawable.java b/jzy3d-api/src/api/org/jzy3d/plot3d/transform/TranslateDrawable.java index aa3d2200..5e694302 100644 --- a/jzy3d-api/src/api/org/jzy3d/plot3d/transform/TranslateDrawable.java +++ b/jzy3d-api/src/api/org/jzy3d/plot3d/transform/TranslateDrawable.java @@ -10,70 +10,66 @@ import org.jzy3d.plot3d.rendering.compat.GLES2CompatUtils; /** Translate drawable to (0,0,0) or back to its previous position. */ public class TranslateDrawable implements Transformer { - public TranslateDrawable(AbstractDrawable drawable, boolean reverse) { - super(); - this.reverse = reverse; - this.drawable = drawable; - } + public TranslateDrawable(AbstractDrawable drawable, boolean reverse) { + super(); + this.reverse = reverse; + this.drawable = drawable; + } - public void execute(GL gl) { - if (drawable != null) { - BoundingBox3d bounds = drawable.getBounds(); - if (bounds != null) { - Coord3d center = bounds.getCenter(); + public void execute(GL gl) { + if (drawable != null) { + BoundingBox3d bounds = drawable.getBounds(); + if (bounds != null) { + Coord3d center = bounds.getCenter(); - if (gl.isGLES()) { - float reverseCoef = (reverse ? -1.0f : 1.0f); - GLES2CompatUtils.glTranslatef(reverseCoef * center.x - / 2, reverseCoef * center.y / 2, reverseCoef - * center.z / 2); - } else { - if (reverse) - gl.getGL2().glTranslatef(-center.x / 2, -center.y / 2, - -center.z / 2); - else - gl.getGL2().glTranslatef(center.x / 2, center.y / 2, - center.z / 2); - } + if (gl.isGLES()) { + float reverseCoef = (reverse ? -1.0f : 1.0f); + GLES2CompatUtils.glTranslatef(reverseCoef * center.x / 2, reverseCoef * center.y / 2, reverseCoef * center.z / 2); + } else { + if (reverse) + gl.getGL2().glTranslatef(-center.x / 2, -center.y / 2, -center.z / 2); + else + gl.getGL2().glTranslatef(center.x / 2, center.y / 2, center.z / 2); + } - } - } - } + } + } + } - public Coord3d compute(Coord3d input) { - if (drawable != null) { - BoundingBox3d bounds = drawable.getBounds(); - if (bounds != null) { - Coord3d center = bounds.getCenter(); - if (reverse) - return input.sub(center.div(2)); - else - return input.add(center.div(2)); - } - } - return null; - } + public Coord3d compute(Coord3d input) { + if (drawable != null) { + BoundingBox3d bounds = drawable.getBounds(); + if (bounds != null) { + Coord3d center = bounds.getCenter(); + if (reverse) + return input.sub(center.div(2)); + else + return input.add(center.div(2)); + } + } + return null; + } - public AbstractDrawable getDrawable() { - return drawable; - } + public AbstractDrawable getDrawable() { + return drawable; + } - public void setDrawable(AbstractDrawable drawable) { - this.drawable = drawable; - } + public void setDrawable(AbstractDrawable drawable) { + this.drawable = drawable; + } - public boolean isReverse() { - return reverse; - } + public boolean isReverse() { + return reverse; + } - public void setReverse(boolean reverse) { - this.reverse = reverse; - } + public void setReverse(boolean reverse) { + this.reverse = reverse; + } - public String toString() { - return "(TranslateDrawable)" + drawable; - } + public String toString() { + return "(TranslateDrawable)" + drawable; + } - protected AbstractDrawable drawable; - protected boolean reverse; + protected AbstractDrawable drawable; + protected boolean reverse; } diff --git a/jzy3d-api/src/awt/org/jzy3d/chart/factories/AWTChartComponentFactory.java b/jzy3d-api/src/awt/org/jzy3d/chart/factories/AWTChartComponentFactory.java index 3f4cddea..878c251b 100644 --- a/jzy3d-api/src/awt/org/jzy3d/chart/factories/AWTChartComponentFactory.java +++ b/jzy3d-api/src/awt/org/jzy3d/chart/factories/AWTChartComponentFactory.java @@ -29,6 +29,10 @@ import org.jzy3d.plot3d.rendering.view.layout.ColorbarViewportLayout; import org.jzy3d.plot3d.rendering.view.layout.IViewportLayout; public class AWTChartComponentFactory extends ChartComponentFactory { + public static Chart chart() { + return chart(Quality.Intermediate); + } + public static Chart chart(Quality quality) { AWTChartComponentFactory f = new AWTChartComponentFactory(); return f.newChart(quality, Toolkit.newt);