From: Michael G. <gof...@us...> - 2007-06-18 12:51:43
|
Update of /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv2339/src/org/octave/graphics Modified Files: AxesObject.java GLRenderer.java GLTextRenderer.java GraphicObject.java ImageObject.java LineObject.java PatchObject.java Renderer.java SurfaceObject.java TextObject.java Added Files: SimpleTextEngine.java Log Message: initial support for logarithmic scales + move text engine to a re-usable location (used now by ticks as well) Index: AxesObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/AxesObject.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- AxesObject.java 31 May 2007 15:11:37 -0000 1.5 +++ AxesObject.java 18 Jun 2007 12:51:42 -0000 1.6 @@ -30,6 +30,59 @@ public class AxesObject extends HandleObject { + public interface Scaler + { + public double scale(double x); + public double[] scale(double[] x); + public double[][] scale(double[][] x); + public double unscale(double x); + public boolean isLinear(); + } + + private class LinearScaler implements Scaler + { + public double scale(double x) { return x; } + public double[] scale(double[] x) { return x; } + public double[][] scale(double[][] x) { return x; } + public double unscale(double x) { return x; } + public boolean isLinear() { return true; } + } + + private class LogScaler implements Scaler + { + public double scale(double x) + { + return Math.log10(x); + } + + public double[] scale(double[] x) + { + double[] y = new double[x.length]; + for (int i=0; i<x.length; i++) + y[i] = Math.log10(x[i]); + return y; + } + + public double[][] scale(double[][] x) + { + double[][] y = new double[x.length][x.length > 0 ? x[0].length : 0]; + for (int i=0; i<x.length; i++) + for (int j=0; j<x[0].length; j++) + y[i][j] = Math.log10(x[i][j]); + return y; + } + + public double unscale(double x) + { + return Math.pow(10, x); + } + + public boolean isLinear() + { + return false; + } + } + /* private double anglex; private double anglez; @@ -67,6 +120,7 @@ private Stack zoomStack = new Stack(); private Rectangle boundingBox; protected boolean alwaysDrawBox = true; + Scaler sx, sy, sz, linScale, logScale; /* properties */ RadioProperty ActivePositionProperty; @@ -135,6 +189,9 @@ RadioProperty ZDir; DoubleArrayProperty x_NormRenderTransform; DoubleArrayProperty x_RenderTransform; + RadioProperty XScale; + RadioProperty YScale; + RadioProperty ZScale; public AxesObject(FigureObject fig, boolean init3D) { @@ -154,6 +211,8 @@ V = new int[4]; canvas = fig.getCanvas(); + linScale = new LinearScaler(); + logScale = new LogScaler(); ActivePositionProperty = new RadioProperty(this, "ActivePositionProperty", new String[] {"outerposition", "position"}, "outerposition"); Position = new DoubleArrayProperty(this, "Position", new double[0], -1); @@ -245,6 +304,9 @@ ZDir = new RadioProperty(this, "ZDir", new String[] {"normal", "reverse"}, "normal"); x_NormRenderTransform = new DoubleArrayProperty(this, "x_NormRenderTransform", new double[16], 16); x_RenderTransform = new DoubleArrayProperty(this, "x_RenderTransform", new double[16], 16); + XScale = new RadioProperty(this, "XScale", new String[] {"linear", "log"}, "linear"); + YScale = new RadioProperty(this, "YScale", new String[] {"linear", "log"}, "linear"); + ZScale = new RadioProperty(this, "ZScale", new String[] {"linear", "log"}, "linear"); updatePosition(); autoTick(); @@ -294,6 +356,9 @@ listen(XDir); listen(YDir); listen(ZDir); + listen(XScale); + listen(YScale); + listen(ZScale); legend = null; baseLine = null; @@ -361,6 +426,9 @@ XDir.reset("normal"); YDir.reset("normal"); ZDir.reset("normal"); + XScale.reset("linear"); + YScale.reset("linear"); + ZScale.reset("linear"); autoTick(); autoAspectRatio(); @@ -687,9 +755,9 @@ gl.glGetIntegerv(GL.GL_VIEWPORT, V, 0); } - double xmin = XLim.getArray()[0], xmax = XLim.getArray()[1]; - double ymin = YLim.getArray()[0], ymax = YLim.getArray()[1]; - double zmin = ZLim.getArray()[0], zmax = ZLim.getArray()[1]; + double xmin = sx.scale(XLim.getArray()[0]), xmax = sx.scale(XLim.getArray()[1]); + double ymin = sy.scale(YLim.getArray()[0]), ymax = sy.scale(YLim.getArray()[1]); + double zmin = sz.scale(ZLim.getArray()[0]), zmax = sz.scale(ZLim.getArray()[1]); double xd = (XDir.is("normal") ? 1 : -1); double yd = (YDir.is("normal") ? 1 : -1); @@ -871,14 +939,16 @@ if (xstate != AXE_DEPTH_DIR) { boolean doXGrid = XGrid.isSet() && !XGridStyle.is("none"); - double[] xticks = XTick.getArray(); + double[] xticks = sx.scale(XTick.getArray()); String[] xticklabels = XTickLabel.getArray(); int wmax = 0, hmax = 0; boolean tickAlongZ = Double.isInfinite(fy); + boolean isLog = XScale.is("log"); XColor.setup(gl); for (int i=0; i<xticks.length; i++) { double xf = xticks[i]; + double[] txtPos; // grid line if (doXGrid) @@ -905,7 +975,7 @@ gl.glVertex3d(xf, yPlaneN, zPlaneN+Math.signum(zPlaneN-zPlane)*fz*xticklen*tickdir); } gl.glEnd(); - gl.glRasterPos3d(xf, yPlaneN, zPlane+Math.signum(zPlane-zPlaneN)*fz*xtickoffset); + txtPos = new double[] {xf, yPlaneN, zPlane+Math.signum(zPlane-zPlaneN)*fz*xtickoffset}; } else { @@ -918,15 +988,16 @@ gl.glVertex3d(xf, yPlane+Math.signum(yPlane-yPlaneN)*fy*xticklen*tickdir, zPlane); } gl.glEnd(); - gl.glRasterPos3d(xf, yPlaneN+Math.signum(yPlaneN-yPlane)*fy*xtickoffset, zPlane); + txtPos = new double[] {xf, yPlaneN+Math.signum(yPlaneN-yPlane)*fy*xtickoffset, zPlane}; } // tick text if (i < xticklabels.length) { - Dimension d = GLTextRenderer.draw(canvas, gl, xticklabels[i], - (xstate == AXE_HORZ_DIR ? 1 : (/*xv[2]*yv[2] >= 0*/ xySym ? 0 : 2)), - (xstate == AXE_VERT_DIR ? 1 : (zd*zv[2] <= 0 ? 2 : 0))); + String txt = (isLog ? "10^{"+xticklabels[i]+"}" : xticklabels[i]); + Dimension d = SimpleTextEngine.draw(canvas, txt, txtPos, + (xstate == AXE_HORZ_DIR ? 1 : (/*xv[2]*yv[2] >= 0*/ xySym ? 0 : 2)), + (xstate == AXE_VERT_DIR ? 1 : (zd*zv[2] <= 0 ? 2 : 0))); if (d.width > wmax) wmax = d.width; if (d.height > hmax) hmax = d.height; } @@ -962,7 +1033,7 @@ p[1] += hmax; break; } - x_renderInv.transform(p[0], p[1], p[2], p, 0); + unTransform(p[0], p[1], p[2], p, 0); xLabObj.Position.reset(new double[] {p[0], p[1], p[2]}); if (xLabObj.Rotation.doubleValue() != angle) try { xLabObj.Rotation.set(new Double(angle)); } @@ -977,14 +1048,16 @@ if (ystate != AXE_DEPTH_DIR) { boolean doYGrid = YGrid.isSet() && !YGridStyle.is("none"); - double[] yticks = YTick.getArray(); + double[] yticks = sy.scale(YTick.getArray()); String[] yticklabels = YTickLabel.getArray(); int wmax = 0, hmax = 0; boolean tickAlongZ = Double.isInfinite(fx); + boolean isLog = YScale.is("log"); YColor.setup(gl); for (int i=0; i<yticks.length; i++) { double yf = yticks[i]; + double[] txtPos; // grid line if (doYGrid) @@ -1011,7 +1084,7 @@ gl.glVertex3d(xPlaneN, yf, zPlaneN+Math.signum(zPlaneN-zPlane)*fz*yticklen*tickdir); } gl.glEnd(); - gl.glRasterPos3d(xPlaneN, yf, zPlane+Math.signum(zPlane-zPlaneN)*fz*ytickoffset); + txtPos = new double[] {xPlaneN, yf, zPlane+Math.signum(zPlane-zPlaneN)*fz*ytickoffset}; } else { @@ -1024,13 +1097,14 @@ gl.glVertex3d(xPlane+Math.signum(xPlane-xPlaneN)*fx*yticklen*tickdir, yf, zPlane); } gl.glEnd(); - gl.glRasterPos3d(xPlaneN+Math.signum(xPlaneN-xPlane)*fx*ytickoffset, yf, zPlane); + txtPos = new double[]{xPlaneN+Math.signum(xPlaneN-xPlane)*fx*ytickoffset, yf, zPlane}; } // tick text if (i < yticklabels.length) { - Dimension d = GLTextRenderer.draw(canvas, gl, yticklabels[i], + String txt = (isLog ? "10^{"+yticklabels[i]+"}" : yticklabels[i]); + Dimension d = SimpleTextEngine.draw(canvas, txt, txtPos, (ystate == AXE_HORZ_DIR ? 1 : (/*xv[2]*yv[2] < 0*/ !xySym ? 0 : 2)), (ystate == AXE_VERT_DIR ? 1 : (zd*zv[2] <= 0 ? 2 : 0))); if (d.width > wmax) wmax = d.width; @@ -1068,7 +1142,7 @@ p[1] += hmax; break; } - x_renderInv.transform(p[0], p[1], p[2], p, 0); + unTransform(p[0], p[1], p[2], p, 0); yLabObj.Position.reset(new double[] {p[0], p[1], p[2]}); if (yLabObj.Rotation.doubleValue() != angle) try { yLabObj.Rotation.set(new Double(angle)); } @@ -1083,13 +1157,15 @@ if (zstate != AXE_DEPTH_DIR) { boolean doZGrid = ZGrid.isSet() && !ZGridStyle.is("none"); - double[] zticks = ZTick.getArray(); + double[] zticks = sz.scale(ZTick.getArray()); int wmax = 0, hmax = 0; String[] zticklabels = ZTickLabel.getArray(); + boolean isLog = ZScale.is("log"); ZColor.setup(gl); for (int i=0; i<zticks.length; i++) { double zf = zticks[i]; + double[] txtPos; // grid line if (doZGrid) @@ -1118,16 +1194,15 @@ gl.glVertex3d(xPlane+Math.signum(xPlane-xPlaneN)*fx*zticklen*tickdir, yPlane, zf); } gl.glEnd(); - gl.glRasterPos3d(xPlaneN+Math.signum(xPlaneN-xPlane)*fx*ztickoffset, yPlane, zf); + txtPos = new double[] {xPlaneN+Math.signum(xPlaneN-xPlane)*fx*ztickoffset, yPlane, zf}; } else { gl.glBegin(GL.GL_LINES); gl.glVertex3d(xPlaneN, yPlane, zf); gl.glVertex3d(xPlaneN, yPlane+Math.signum(yPlane-yPlaneN)*fy*zticklen*tickdir, zf); - gl.glEnd(); - gl.glRasterPos3d(xPlaneN, yPlane+Math.signum(yPlane-yPlaneN)*fy*ztickoffset, zf); + txtPos = new double[] {xPlaneN, yPlane+Math.signum(yPlane-yPlaneN)*fy*ztickoffset, zf}; } } else @@ -1143,7 +1218,7 @@ gl.glVertex3d(xPlane, yPlane+Math.signum(yPlane-yPlaneN)*fy*zticklen*tickdir, zf); } gl.glEnd(); - gl.glRasterPos3d(xPlane, yPlaneN+Math.signum(yPlaneN-yPlane)*fy*ztickoffset, zf); + txtPos = new double[] {xPlane, yPlaneN+Math.signum(yPlaneN-yPlane)*fy*ztickoffset, zf}; } else { @@ -1151,14 +1226,15 @@ gl.glVertex3d(xPlane, yPlaneN, zf); gl.glVertex3d(xPlane+Math.signum(xPlane-xPlaneN)*fx*zticklen*tickdir, yPlaneN, zf); gl.glEnd(); - gl.glRasterPos3d(xPlane+Math.signum(xPlane-xPlaneN)*fx*ztickoffset, yPlaneN, zf); + txtPos = new double[] {xPlane+Math.signum(xPlane-xPlaneN)*fx*ztickoffset, yPlaneN, zf}; } } // tick text if (i < zticklabels.length) { - Dimension d = GLTextRenderer.draw(canvas, gl, zticklabels[i], + String txt = (isLog ? "10^{"+zticklabels[i]+"}" : zticklabels[i]); + Dimension d = SimpleTextEngine.draw(canvas, txt, txtPos, 2, (zstate == AXE_VERT_DIR ? 1 : (zd*zv[2] < 0 ? 0 : 2))); if (d.width > wmax) wmax = d.width; @@ -1217,7 +1293,7 @@ p[1] += hmax; break; } - x_renderInv.transform(p[0], p[1], p[2], p, 0); + unTransform(p[0], p[1], p[2], p, 0); zLabObj.Position.reset(new double[] {p[0], p[1], p[2]}); if (zLabObj.Rotation.doubleValue() != angle) try { zLabObj.Rotation.set(new Double(angle)); } @@ -1239,7 +1315,7 @@ // position title automatically Rectangle bb = getBoundingBox(); double[] p = new double[3]; - x_renderInv.transform(bb.x+bb.width/2, canvas.getHeight()-(bb.y+bb.height+10), (x_zmin+x_zmax)/2, p, 0); + unTransform(bb.x+bb.width/2, canvas.getHeight()-(bb.y+bb.height+10), (x_zmin+x_zmax)/2, p, 0); titleObj.Position.reset(p); } titleObj.draw(r); @@ -1385,41 +1461,74 @@ autoScaleZ(); } - protected void autoScaleX() + protected double[] computeAutoScale(String Lim, RadioProperty Scale, boolean isZ) { - if (XLimMode.is("auto") && Children.size() > 0) - { - double[] xlim = { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }; + double[] lim; + String LimInclude = Lim+"Include"; - for (int i=0; i<Children.size(); i++) + if (Scale.is("linear")) { - GraphicObject go = (GraphicObject)Children.elementAt(i); - if (go.XLimInclude.isSet()) + lim = new double[] { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }; + for (int i=0; i<Children.size(); i++) { - double[] _xlim = go.XLim.getArray(); - xlim[0] = Math.min(_xlim[0], xlim[0]); - xlim[1] = Math.max(_xlim[1], xlim[1]); + GraphicObject go = (GraphicObject)Children.elementAt(i); + if (((BooleanProperty)go.getProperty(LimInclude)).isSet()) + { + double[] _lim = ((DoubleArrayProperty)go.getProperty(Lim)).getArray(); + lim[0] = Math.min(_lim[0], lim[0]); + lim[1] = Math.max(_lim[1], lim[1]); + } } - } - if (xlim[0] > xlim[1]) - { - xlim[0] = 0; - xlim[1] = 1; + if (lim[0] > lim[1]) + { + lim[0] = (isZ ? -0.5 : 0); + lim[1] = (isZ ? 0.5 : 1); + } + else if (lim[0] == lim[1]) + { + lim[0] -= 0.5; + lim[1] += 0.5; + } + + double dl = lim[1]-lim[0]; + if (dl > 10) + { + lim[0] = Math.floor(lim[0]); + lim[1] = Math.ceil(lim[1]); + } } - else if (xlim[0] == xlim[1]) + else { - xlim[0] -= 0.5; - xlim[1] += 0.5; - } + lim = new double[] { Double.POSITIVE_INFINITY, Double.MIN_VALUE }; + for (int i=0; i<Children.size(); i++) + { + GraphicObject go = (GraphicObject)Children.elementAt(i); + if (((BooleanProperty)go.getProperty(LimInclude)).isSet()) + { + double[] _lim = ((DoubleArrayProperty)go.getProperty(Lim)).getArray(); + lim[0] = Math.min(_lim[2], lim[0]); + lim[1] = Math.max(_lim[3], lim[1]); + } + } - double dx = xlim[1]-xlim[0]; - if (dx > 10) - { - xlim[0] = Math.floor(xlim[0]); - xlim[1] = Math.ceil(xlim[1]); + if (lim[0] > lim[1]) + { + lim[0] = 1; + lim[1] = 10; + } + lim[0] = Math.pow(10, Math.floor(Math.log10(lim[0]))); + lim[1] = Math.pow(10, Math.ceil(Math.log10(lim[1]))); } + return lim; + } + + protected void autoScaleX() + { + if (XLimMode.is("auto") && Children.size() > 0) + { + double[] xlim = computeAutoScale("XLim", XScale, false); autoSet(XLim, xlim); autoTickX(); } @@ -1429,37 +1538,7 @@ { if (YLimMode.is("auto") && Children.size() > 0) { - double[] ylim = { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }; - - for (int i=0; i<Children.size(); i++) - { - GraphicObject go = (GraphicObject)Children.elementAt(i); - if (go.YLimInclude.isSet()) - { - double[] _ylim = go.YLim.getArray(); - ylim[0] = Math.min(_ylim[0], ylim[0]); - ylim[1] = Math.max(_ylim[1], ylim[1]); - } - } - - if (ylim[0] > ylim[1]) - { - ylim[0] = 0; - ylim[1] = 1; - } - else if (ylim[0] == ylim[1]) - { - ylim[0] -= 0.5; - ylim[1] += 0.5; - } - - double dx = ylim[1]-ylim[0]; - if (dx > 10) - { - ylim[0] = Math.floor(ylim[0]); - ylim[1] = Math.ceil(ylim[1]); - } - + double[] ylim = computeAutoScale("YLim", YScale, false); autoSet(YLim, ylim); autoTickY(); } @@ -1469,37 +1548,7 @@ { if (ZLimMode.is("auto") && Children.size() > 0) { - double[] zlim = { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }; - - for (int i=0; i<Children.size(); i++) - { - GraphicObject go = (GraphicObject)Children.elementAt(i); - if (go.ZLimInclude.isSet()) - { - double[] _zlim = go.ZLim.getArray(); - zlim[0] = Math.min(_zlim[0], zlim[0]); - zlim[1] = Math.max(_zlim[1], zlim[1]); - } - } - - if (zlim[0] > zlim[1]) - { - zlim[0] = -0.5; - zlim[1] = 0.5; - } - else if (zlim[0] == zlim[1]) - { - zlim[0] -= 0.5; - zlim[1] += 0.5; - } - - double dx = zlim[1]-zlim[0]; - if (dx > 10) - { - zlim[0] = Math.floor(zlim[0]); - zlim[1] = Math.ceil(zlim[1]); - } - + double[] zlim = computeAutoScale("ZLim", ZScale, true); autoSet(ZLim, zlim); autoTickZ(); } @@ -1548,14 +1597,32 @@ autoTickZ(); } + protected double[] computeAutoTicks(DoubleArrayProperty Lim, RadioProperty Scale) + { + double vmin = Lim.getArray()[0], vmax = Lim.getArray()[1]; + double[] ticks; + if (Scale.is("linear")) + { + ticks = new double[5]; + for (int i=0; i<ticks.length; i++) + ticks[i] = vmin + i * (vmax - vmin) / (ticks.length - 1); + } + else + { + int n1 = (int)Math.ceil(Math.log10(vmin)), + n2 = (int)Math.floor(Math.log10(vmax)); + ticks = new double[n2-n1+1]; + for (int i=0; i<ticks.length; i++) + ticks[i] = Math.pow(10, n1+i); + } + return ticks; + } + protected void autoTickX() { if (XTickMode.is("auto")) { - double xmin = XLim.getArray()[0], xmax = XLim.getArray()[1]; - double[] ticks = new double[5]; - for (int i=0; i<ticks.length; i++) - ticks[i] = xmin + i * (xmax - xmin) / (ticks.length - 1); + double[] ticks = computeAutoTicks(XLim, XScale); autoSet(XTick, ticks); } autoTickLabelX(); @@ -1565,10 +1632,7 @@ { if (YTickMode.is("auto")) { - double ymin = YLim.getArray()[0], ymax = YLim.getArray()[1]; - double[] ticks = new double[5]; - for (int i=0; i<ticks.length; i++) - ticks[i] = ymin + i * (ymax - ymin) / (ticks.length - 1); + double[] ticks = computeAutoTicks(YLim, YScale); autoSet(YTick, ticks); } autoTickLabelY(); @@ -1578,10 +1642,7 @@ { if (ZTickMode.is("auto")) { - double zmin = ZLim.getArray()[0], zmax = ZLim.getArray()[1]; - double[] ticks = new double[5]; - for (int i=0; i<ticks.length; i++) - ticks[i] = zmin + i * (zmax - zmin) / (ticks.length - 1); + double[] ticks = computeAutoTicks(ZLim, ZScale); autoSet(ZTick, ticks); } autoTickLabelZ(); @@ -1594,40 +1655,45 @@ autoTickLabelZ(); } - protected void autoTickLabelX() + protected String[] computeAutoTickLabels(DoubleArrayProperty Tick, RadioProperty Scale) { - double[] ticks = XTick.getArray(); + double[] ticks = Tick.getArray(); String[] labels = new String[ticks.length]; - for (int i=0; i<ticks.length; i++) + if (Scale.is("linear")) + for (int i=0; i<ticks.length; i++) + { + double val = ((double)Math.round(ticks[i]*100))/100; + labels[i] = Double.toString(val); + } + else { - double val = ((double)Math.round(ticks[i]*100))/100; - labels[i] = new Double(val).toString(); + for (int i=0; i<ticks.length; i++) + { + double v = Math.log10(ticks[i]); + if ((int)v == v) + labels[i] = Integer.toString((int)v); + else + labels[i] = Double.toString(v); + } } + return labels; + } + + protected void autoTickLabelX() + { + String[] labels = computeAutoTickLabels(XTick, XScale); autoSet(XTickLabel, labels); } protected void autoTickLabelY() { - double[] ticks = YTick.getArray(); - String[] labels = new String[ticks.length]; - for (int i=0; i<ticks.length; i++) - { - double val = ((double)Math.round(ticks[i]*100))/100; - labels[i] = new Double(val).toString(); - } + String[] labels = computeAutoTickLabels(YTick, YScale); autoSet(YTickLabel, labels); - } protected void autoTickLabelZ() { - double[] ticks = ZTick.getArray(); - String[] labels = new String[ticks.length]; - for (int i=0; i<ticks.length; i++) - { - double val = ((double)Math.round(ticks[i]*100))/100; - labels[i] = new Double(val).toString(); - } + String[] labels = computeAutoTickLabels(ZTick, ZScale); autoSet(ZTickLabel, labels); } @@ -1703,8 +1769,8 @@ { double[] pos1 = new double[3], pos2 = new double[3]; - x_renderInv.transform((double)x1, (double)y1, (x_zmin+x_zmax)/2, pos1, 0); - x_renderInv.transform((double)x2, (double)y2, (x_zmin+x_zmax)/2, pos2, 0); + unTransform((double)x1, (double)y1, (x_zmin+x_zmax)/2, pos1, 0); + unTransform((double)x2, (double)y2, (x_zmin+x_zmax)/2, pos2, 0); zoomStack.push(XLimMode.get()); zoomStack.push(XLim.get()); zoomStack.push(YLimMode.get()); @@ -1869,7 +1935,7 @@ { Rectangle bb = getBoundingBox(); p = new double[3]; - x_renderInv.transform(bb.x+pos[0], bb.y+pos[1], pos[2], p, 0); + unTransform(bb.x+pos[0], bb.y+pos[1], pos[2], p, 0); } else { @@ -1882,7 +1948,7 @@ if (toUnits.equalsIgnoreCase("pixels")) { Rectangle bb = getBoundingBox(); - x_render.transform(p[0], p[1], p[2], p, 0); + transform(p[0], p[1], p[2], p, 0); p[0] = Math.rint(p[0])-bb.x; p[1] = Math.rint(p[1])-bb.y; } @@ -2142,10 +2208,17 @@ Position.reset(fig.convertPosition(Position.getArray(), currentUnits, Units.getValue())); currentUnits = Units.getValue(); } + else if (p == XScale) + autoScaleX(); + else if (p == YScale) + autoScaleY(); + else if (p == ZScale) + autoScaleZ(); if (autoMode == 0 && (p == XLim || p == YLim || p == ZLim || p == XLimMode || p == YLimMode || p == ZLimMode || - p == XDir || p == YDir || p == ZDir || p == Position || p == OuterPosition)) + p == XDir || p == YDir || p == ZDir || p == Position || p == OuterPosition || + p == XScale || p == YScale || p == ZScale)) { zoomStack.clear(); autoAspectRatio(); @@ -2180,15 +2253,37 @@ Matrix3D x_mat2 = new Matrix3D(); double x_zmin, x_zmax; + public void updateScalers() + { + sx = (XScale.is("linear") ? linScale : logScale); + sy = (YScale.is("linear") ? linScale : logScale); + sz = (ZScale.is("linear") ? linScale : logScale); + } + + public void unTransform(double x, double y, double z, double[] p, int offset) + { + x_renderInv.transform(x, y, z, p, offset); + p[0+offset] = sx.unscale(p[0+offset]); + p[1+offset] = sy.unscale(p[1+offset]); + p[2+offset] = sz.unscale(p[2+offset]); + } + + public void transform(double x, double y, double z, double[] p, int offset) + { + x_render.transform(sx.scale(x), sy.scale(y), sz.scale(z), p, offset); + } + public void updateXFormMatrices() { + updateScalers(); + double xd = (XDir.is("normal") ? 1 : -1); double yd = (YDir.is("normal") ? 1 : -1); double zd = (ZDir.is("normal") ? 1 : -1); - double[] xlim = XLim.getArray(); - double[] ylim = YLim.getArray(); - double[] zlim = ZLim.getArray(); + double[] xlim = sx.scale(XLim.getArray()); + double[] ylim = sy.scale(YLim.getArray()); + double[] zlim = sz.scale(ZLim.getArray()); double xo = xlim[xd > 0 ? 0 : 1]; double yo = ylim[yd > 0 ? 0 : 1]; Index: ImageObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/ImageObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- ImageObject.java 31 May 2007 14:44:22 -0000 1.2 +++ ImageObject.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -38,8 +38,7 @@ XData = new DoubleArrayProperty(this, "XData", new double[] {1, cdata[0].length}, 2); YData = new DoubleArrayProperty(this, "YData", new double[] {1, cdata.length}, 2); - XLim.reset(XData.getArray()); - YLim.reset(YData.getArray()); + updateMinMax(); } public ImageObject(HandleObject parent, double[][] r, double[][] g, double[][] b) @@ -59,12 +58,46 @@ XData = new DoubleArrayProperty(this, "XData", new double[] {1, r[0].length}, 2); YData = new DoubleArrayProperty(this, "YData", new double[] {1, r.length}, 2); - XLim.reset(XData.getArray()); - YLim.reset(YData.getArray()); + updateMinMax(); + } + + private void updateMinMax() + { + double[] x = XData.getArray(), y = YData.getArray(); + int h = CData.getDim(0), w = CData.getDim(1); + double px = (x[1]-x[0])/(w-1), py = (y[1]-y[0])/(h-1); + double xmin, xmax, ymin, ymax, xmin2, xmax2, ymin2, ymax2; + + xmin = xmin2 = x[0]-px/2; xmax = xmax2 = x[1]+px/2; + ymin = ymin2 = y[0]-py/2; ymax = ymax2 = y[1]+py/2; + if (xmax2 <= 0) + { + xmin2 = Double.POSITIVE_INFINITY; + xmax2 = Double.MIN_VALUE; + } + else if (xmin2 <= 0) + { + double k = Math.ceil(0.5-x[0]/px); + xmin2 = x[0]+(k-0.5)*px; + } + if (ymax2 <= 0) + { + ymin2 = Double.POSITIVE_INFINITY; + ymax2 = Double.MIN_VALUE; + } + else if (ymin2 <= 0) + { + double k = Math.ceil(0.5-y[0]/py); + ymin2 = y[0]+(k-0.5)*py; + } + + XLim.set(new double[] {xmin, xmax, xmin2, xmax2}, true); + YLim.set(new double[] {ymin, ymax, ymin2, ymax2}, true); } public void validate() { + updateMinMax(); super.validate(); } Index: GraphicObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/GraphicObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- GraphicObject.java 31 May 2007 14:44:22 -0000 1.2 +++ GraphicObject.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -45,13 +45,15 @@ glID = glIDCounter++; - double[] d = new double[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}; + double[] d1 = new double[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, Double.MIN_VALUE}; + double[] d2 = new double[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}; - XLim = new DoubleArrayProperty(this, "XLim", d, 2); - YLim = new DoubleArrayProperty(this, "YLim", d, 2); - ZLim = new DoubleArrayProperty(this, "ZLim", d, 2); - CLim = new DoubleArrayProperty(this, "CLim", d, 2); - ALim = new DoubleArrayProperty(this, "ALim", d, 2); + XLim = new DoubleArrayProperty(this, "XLim", d1, 4); + YLim = new DoubleArrayProperty(this, "YLim", d1, 4); + ZLim = new DoubleArrayProperty(this, "ZLim", d1, 4); + CLim = new DoubleArrayProperty(this, "CLim", d2, 2); + ALim = new DoubleArrayProperty(this, "ALim", d2, 2); XLimInclude = new BooleanProperty(this, "XLimInclude", true); YLimInclude = new BooleanProperty(this, "YLimInclude", true); ZLimInclude = new BooleanProperty(this, "ZLimInclude", false); Index: Renderer.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/Renderer.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- Renderer.java 31 May 2007 14:44:23 -0000 1.2 +++ Renderer.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -22,6 +22,7 @@ package org.octave.graphics; import java.awt.*; +import java.awt.image.*; import java.nio.ByteBuffer; public interface Renderer @@ -74,6 +75,8 @@ public void draw(ByteBuffer data, int w, int h, double[] pos, int xOffset, int yOffset, boolean useClipping, boolean useZBuffer); + + public void drawBitmap(BufferedImage img, double[] pos, int xOffset, int yOffset); public void draw(PatchObject patch); Index: SurfaceObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/SurfaceObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- SurfaceObject.java 31 May 2007 14:44:23 -0000 1.2 +++ SurfaceObject.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -94,6 +94,7 @@ private void updateMinMax() { double xmin, xmax, ymin, ymax, zmin, zmax; + double xmin2, xmax2, ymin2, ymax2, zmin2, zmax2; double[][] x = XData.getMatrix(); double[][] y = YData.getMatrix(); @@ -102,24 +103,40 @@ int m = Math.min(Math.min(x.length, y.length), z.length); int n = (m > 0 ? Math.min(Math.min(x[0].length, y[0].length), z[0].length) : 0); - xmin = x[0][0]; xmax = x[0][0]; - ymin = y[0][0]; ymax = y[0][0]; - zmin = z[0][0]; zmax = z[0][0]; + xmin = ymin = zmin = Double.POSITIVE_INFINITY; + xmax = ymax = zmax = Double.NEGATIVE_INFINITY; + xmin2 = ymin2 = zmin2 = Double.POSITIVE_INFINITY; + xmax2 = ymax2 = zmax2 = Double.MIN_VALUE; for (int i=0; i<m; i++) for (int j=0; j<n; j++) { if (x[i][j] < xmin) xmin = x[i][j]; else if (x[i][j] > xmax) xmax = x[i][j]; + if (x[i][j] > 0) + { + if (x[i][j] < xmin2) xmin2 = x[i][j]; + else if (x[i][j] > xmax2) xmax2 = x[i][j]; + } if (y[i][j] < ymin) ymin = y[i][j]; else if (y[i][j] > ymax) ymax = y[i][j]; + if (y[i][j] > 0) + { + if (y[i][j] < ymin2) ymin2 = y[i][j]; + else if (y[i][j] > ymax2) ymax2 = y[i][j]; + } if (z[i][j] < zmin) zmin = z[i][j]; else if (z[i][j] > zmax) zmax = z[i][j]; + if (z[i][j] > 0) + { + if (z[i][j] < zmin2) zmin2 = z[i][j]; + else if (z[i][j] > zmax2) zmax2 = z[i][j]; + } } - XLim.set(new double[] {xmin, xmax}, true); - YLim.set(new double[] {ymin, ymax}, true); - ZLim.set(new double[] {zmin, zmax}, true); + XLim.set(new double[] {xmin, xmax, xmin2, xmax2}, true); + YLim.set(new double[] {ymin, ymax, ymin2, ymax2}, true); + ZLim.set(new double[] {zmin, zmax, zmin2, zmax2}, true); } private void updateColorMinMax() Index: GLRenderer.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/GLRenderer.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- GLRenderer.java 8 Jun 2007 12:26:34 -0000 1.4 +++ GLRenderer.java 18 Jun 2007 12:51:42 -0000 1.5 @@ -22,6 +22,7 @@ package org.octave.graphics; import java.awt.Color; +import java.awt.image.*; import javax.media.opengl.*; import javax.media.opengl.glu.*; import java.nio.ByteBuffer; @@ -44,6 +45,7 @@ private TreeMap alphaPrimitives; private GLUtessellator tess = null; private int lightSideMode = GL.GL_FRONT_AND_BACK; + private AxesObject.Scaler sx, sy, sz; public GLRenderer(GLAutoDrawable d) { @@ -124,13 +126,14 @@ (y > ymax ? 1 : 0) << 3 | (z < zmin ? 1 : 0) << 4 | (z > zmax ? 1 : 0) << 5 | - (isNaN(x, y, z) ? 0 : 1) << 6 + (isNaNorInf(x, y, z) ? 0 : 1) << 6 ); } - public boolean isNaN(double x, double y, double z) + public boolean isNaNorInf(double x, double y, double z) { - return (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z)); + return (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z) || + Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z)); } public void setCamera(double[] pos, double[] target) @@ -232,9 +235,9 @@ public void draw(LineObject line) { - double[] x = line.XData.getArray(); - double[] y = line.YData.getArray(); - double[] z = line.ZData.getArray(); + double[] x = sx.scale(line.XData.getArray()); + double[] y = sy.scale(line.YData.getArray()); + double[] z = sz.scale(line.ZData.getArray()); int n = Math.min(Math.min(x.length, y.length), (z.length == 0 ? Integer.MAX_VALUE : z.length)); int[] clip = new int[n]; @@ -373,7 +376,7 @@ gl.glDisable(GL.GL_DEPTH_TEST); gl.glEnable(GL.GL_ALPHA_TEST); gl.glAlphaFunc(GL.GL_GREATER, 0.0f); - gl.glRasterPos3d(pos[0], pos[1], pos[2]); + gl.glRasterPos3d(sx.scale(pos[0]), sy.scale(pos[1]), sz.scale(pos[2])); gl.glBitmap(0, 0, 0, 0, -xOffset, -yOffset, null, 0); gl.glDrawPixels(w, h, GL.GL_ABGR_EXT, GL.GL_UNSIGNED_BYTE, data); gl.glDisable(GL.GL_ALPHA_TEST); @@ -383,6 +386,16 @@ setClipping(!useClipping); } + public void drawBitmap(BufferedImage img, double[] pos, int xOffset, int yOffset) + { + byte[] data = ((DataBufferByte)img.getData().getDataBuffer()).getData(); + gl.glRasterPos3d(pos[0], pos[1], pos[2]); + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glBitmap(0, 0, 0, 0, xOffset, yOffset, null, 0); + gl.glBitmap(img.getWidth(), img.getHeight(), 0, 0, 0, 0, data, 0); + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 4); + } + private class VertexData { double[] coords; @@ -730,10 +743,26 @@ } } + /* scale 3D points */ + private double[][] scale(double[][] pts) + { + if (sx.isLinear() && sy.isLinear() && sz.isLinear()) + return pts; + + double[][] out = new double[pts.length][3]; + for (int i=0; i<pts.length; i++) + { + out[i][0] = sx.scale(pts[i][0]); + out[i][1] = sy.scale(pts[i][1]); + out[i][2] = sz.scale(pts[i][2]); + } + return out; + } + public void draw(PatchObject patch) { double[][] f = patch.Faces.getMatrix(); - double[][] v = patch.Vertices.getMatrix(); + double[][] v = scale(patch.Vertices.getMatrix()); double[][] c = null; double[][] n = patch.VertexNormals.getMatrix(); double[] a = null; @@ -756,6 +785,17 @@ float ss = patch.SpecularStrength.floatValue(); float se = patch.SpecularExponent.floatValue(); + boolean[] clip = new boolean[v.length]; + for (int i=0; i<v.length; i++) + clip[i] = isNaNorInf(v[i][0], v[i][1], v[i][2]); + boolean[] clipF = new boolean[f.length]; + for (int i=0; i<f.length; i++) + { + clipF[i] = false; + for (int j=0; j<faceCount[i] && !clipF[i]; j++) + clipF[i] = (clipF[i] || clip[(int)f[i][j]-1]); + } + if (!patch.FaceColor.isSet() || !patch.EdgeColor.isSet()) { c = patch.getCData(); @@ -821,6 +861,9 @@ for (int i=0; i<f.length; i++) { + if (clipF[i]) + continue; + glu.gluTessBeginPolygon(tess, vData[i][0]); glu.gluTessBeginContour(tess); for (int j=0; j<faceCount[i]; j++) @@ -849,6 +892,9 @@ for (int i=0; i<f.length; i++) { + if (clipF[i]) + continue; + glu.gluTessBeginPolygon(tess, vData[i][0]); glu.gluTessBeginContour(tess); for (int j=0; j<faceCount[i]; j++) @@ -892,6 +938,9 @@ for (int i=0; i<f.length; i++) { + if (clipF[i]) + continue; + glu.gluTessBeginPolygon(tess, vData[i][0]); glu.gluTessBeginContour(tess); for (int j=0; j<faceCount[i]; j++) @@ -920,6 +969,9 @@ for (int i=0; i<f.length; i++) { + if (clipF[i]) + continue; + glu.gluTessBeginPolygon(tess, vData[i][0]); glu.gluTessBeginContour(tess); for (int j=0; j<faceCount[i]; j++) @@ -937,9 +989,9 @@ public void draw(SurfaceObject surf) { - double[][] x = surf.XData.getMatrix(); - double[][] y = surf.YData.getMatrix(); - double[][] z = surf.ZData.getMatrix(); + double[][] x = sx.scale(surf.XData.getMatrix()); + double[][] y = sy.scale(surf.YData.getMatrix()); + double[][] z = sz.scale(surf.ZData.getMatrix()); double[][][] c = null; double[][][] n = surf.VertexNormals.getMatrix3(); double[][] a = null; @@ -959,6 +1011,11 @@ final float ss = surf.SpecularStrength.floatValue(); final float se = surf.SpecularExponent.floatValue(); + boolean[][] clip = new boolean[z.length][z.length > 0 ? z[0].length : 0]; + for (int i=0; i<z.length; i++) + for (int j=0; j<z[0].length; j++) + clip[i][j] = isNaNorInf(x[i][j], y[i][j], z[i][j]); + if (faceColorMode > 0 || edgeColorMode > 0) { c = surf.getCData(); @@ -1006,6 +1063,9 @@ for (int i=1; i<x.length; i++) for (int j=1; j<x[i].length; j++) { + if (clip[i-1][j-1] || clip[i-1][j] || clip[i][j-1] || clip[i][j]) + continue; + gl.glBegin(GL.GL_QUADS); // Vertex 1 @@ -1091,6 +1151,9 @@ for (int i=1; i<x.length; i++) for (int j=1; j<x[i].length; j++) { + if (clip[i-1][j-1] || clip[i-1][j] || clip[i][j-1] || clip[i][j]) + continue; + final double[] xx = new double[] {x[i-1][j-1], x[i][j-1], x[i][j], x[i-1][j]}; final double[] yy = new double[] {y[i-1][j-1], y[i][j-1], y[i][j], y[i-1][j]}; final double[] zz = new double[] {z[i-1][j-1], z[i][j-1], z[i][j], z[i-1][j]}; @@ -1190,6 +1253,9 @@ { for (int j=1; j<x[i].length; j++) { + if (clip[i][j-1] || clip[i][j]) + continue; + gl.glBegin(GL.GL_LINES); // Vertex 1 @@ -1234,6 +1300,9 @@ { for (int i=1; i<y.length; i++) { + if (clip[i-1][j] || clip[i][j]) + continue; + gl.glBegin(GL.GL_LINES); // Vertex 1 @@ -1285,6 +1354,9 @@ { for (int j=1; j<x[i].length; j++) { + if (clip[i][j-1] || clip[i][j]) + continue; + final double[] xx = new double[] {x[i][j-1], x[i][j]}; final double[] yy = new double[] {y[i][j-1], y[i][j]}; final double[] zz = new double[] {z[i][j-1], z[i][j]}; @@ -1357,10 +1429,13 @@ } } - for (int j=0; j<y.length; j++) + for (int j=0; j<y[0].length; j++) { - for (int i=1; i<y[j].length; i++) + for (int i=1; i<y.length; i++) { + if (clip[i-1][j] || clip[i][j]) + continue; + final double[] xx = new double[] {x[i-1][j], x[i][j]}; final double[] yy = new double[] {y[i-1][j], y[i][j]}; final double[] zz = new double[] {z[i-1][j], z[i][j]}; @@ -1565,16 +1640,21 @@ double ty = ((double)d.h)/d.texH; double px = (x[1]-x[0])/(d.w-1); double py = (y[1]-y[0])/(d.h-1); + double x1 = sx.scale(x[0]-px/2), x2 = sx.scale(x[1]+px/2); + double y1 = sy.scale(y[0]-py/2), y2 = sy.scale(y[1]+py/2); - gl.glEnable(GL.GL_TEXTURE_2D); - gl.glColor3d(1, 1, 1); - gl.glBegin(GL.GL_QUADS); - gl.glTexCoord2d(0, 0); gl.glVertex3d(x[0]-px/2, y[0]-py/2, (zmin+zmax)/2); - gl.glTexCoord2d(tx, 0); gl.glVertex3d(x[1]+px/2, y[0]-py/2, (zmin+zmax)/2); - gl.glTexCoord2d(tx, ty); gl.glVertex3d(x[1]+px/2, y[1]+py/2, (zmin+zmax)/2); - gl.glTexCoord2d(0, ty); gl.glVertex3d(x[0]-px/2, y[1]+py/2, (zmin+zmax)/2); - gl.glEnd(); - gl.glDisable(GL.GL_TEXTURE_2D); + if (!isNaNorInf(x1, y1, 0) && !isNaNorInf(x2, y2, 0)) + { + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glColor3d(1, 1, 1); + gl.glBegin(GL.GL_QUADS); + gl.glTexCoord2d(0, 0); gl.glVertex3d(x1, y1, (zmin+zmax)/2); + gl.glTexCoord2d(tx, 0); gl.glVertex3d(x2, y1, (zmin+zmax)/2); + gl.glTexCoord2d(tx, ty); gl.glVertex3d(x2, y2, (zmin+zmax)/2); + gl.glTexCoord2d(0, ty); gl.glVertex3d(x1, y2, (zmin+zmax)/2); + gl.glEnd(); + gl.glDisable(GL.GL_TEXTURE_2D); + } } public void setXForm(AxesObject ax) @@ -1595,6 +1675,10 @@ * that previous drawing are always overdrawn (to implement layering) */ gl.glClear(GL.GL_DEPTH_BUFFER_BIT); + + sx = ax.sx; + sy = ax.sy; + sz = ax.sz; } public void setViewport(int width, int height) Index: LineObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/LineObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- LineObject.java 31 May 2007 14:44:22 -0000 1.2 +++ LineObject.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -72,6 +72,7 @@ private void updateMinMax() { double xmin, xmax, ymin, ymax, zmin, zmax; + double xmin2, xmax2, ymin2, ymax2, zmin2, zmax2; double[] xdata = XData.getArray(); double[] ydata = YData.getArray(); double[] zdata = ZData.getArray(); @@ -81,27 +82,46 @@ if (n == 0) return; - xmin = xdata[0]; xmax = xdata[0]; - ymin = ydata[0]; ymax = ydata[0]; - zmin = (hasZ ? zdata[0] : -0.5); zmax = (hasZ ? zdata[0] : 0.5); + xmin = ymin = xmin2 = ymin2 = Double.POSITIVE_INFINITY; + xmax = ymax = Double.NEGATIVE_INFINITY; + xmax2 = ymax2 = Double.MIN_VALUE; + zmin = (hasZ ? Double.POSITIVE_INFINITY : -0.5); + zmax = (hasZ ? Double.NEGATIVE_INFINITY : 0.5); + zmin2 = (hasZ ? Double.POSITIVE_INFINITY : 0.1); + zmax2 = (hasZ ? Double.MIN_VALUE : 1); - for (int i=1; i<n; i++) + for (int i=0; i<n; i++) { if (xdata[i] < xmin) xmin = xdata[i]; else if (xdata[i] > xmax) xmax = xdata[i]; + if (xdata[i] > 0) + { + if (xdata[i] < xmin2) xmin2 = xdata[i]; + else if (xdata[i] > xmax2) xmax2 = xdata[i]; + } if (ydata[i] < ymin) ymin = ydata[i]; else if (ydata[i] > ymax) ymax = ydata[i]; + if (ydata[i] > 0) + { + if (ydata[i] < ymin2) ymin2 = ydata[i]; + else if (ydata[i] > ymax2) ymax2 = ydata[i]; + } if (hasZ) { if (zdata[i] < zmin) zmin = zdata[i]; else if (zdata[i] > zmax) zmax = zdata[i]; + if (zdata[i] > 0) + { + if (zdata[i] < zmin2) zmin2 = zdata[i]; + else if (zdata[i] > zmax2) zmax2 = zdata[i]; + } } } - XLim.set(new double[] {xmin, xmax}, true); - YLim.set(new double[] {ymin, ymax}, true); + XLim.set(new double[] {xmin, xmax, xmin2, xmax2}, true); + YLim.set(new double[] {ymin, ymax, ymin2, ymax2}, true); if (hasZ) - ZLim.set(new double[] {zmin, zmax}, true); + ZLim.set(new double[] {zmin, zmax, zmin2, zmax2}, true); } /* TODO: remove Index: GLTextRenderer.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/GLTextRenderer.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- GLTextRenderer.java 31 May 2007 14:44:22 -0000 1.2 +++ GLTextRenderer.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -25,6 +25,7 @@ import java.awt.image.*; import javax.media.opengl.*; +// TODO: remove and replace with SimpleTextEngine public class GLTextRenderer { public static Dimension draw(RenderCanvas comp, GL gl, String txt, int halign, int valign) Index: PatchObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/PatchObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- PatchObject.java 31 May 2007 14:44:22 -0000 1.2 +++ PatchObject.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -97,31 +97,45 @@ private void updateMinMax() { double xmin, xmax, ymin, ymax, zmin, zmax, cmin, cmax; + double xmin2, xmax2, ymin2, ymax2, zmin2, zmax2; double[][] v = Vertices.getMatrix(); + xmin = ymin = zmin = Double.POSITIVE_INFINITY; + xmax = ymax = zmax = Double.NEGATIVE_INFINITY; + xmin2 = ymin2 = zmin2 = Double.POSITIVE_INFINITY; + xmax2 = ymax2 = zmax2 = Double.MIN_VALUE; + if (v != null && v.length > 0) { - xmin = v[0][0]; ymin = v[0][1]; zmin = v[0][2]; - xmax = v[0][0]; ymax = v[0][1]; zmax = v[0][2]; - for (int i=1; i<v.length; i++) + for (int i=0; i<v.length; i++) { if (v[i][0] < xmin) xmin = v[i][0]; else if (v[i][0] > xmax) xmax = v[i][0]; + if (v[i][0] > 0) + { + if (v[i][0] < xmin2) xmin2 = v[i][0]; + else if (v[i][0] > xmax2) xmax2 = v[i][0]; + } if (v[i][1] < ymin) ymin = v[i][1]; else if (v[i][1] > ymax) ymax = v[i][1]; + if (v[i][1] > 0) + { + if (v[i][1] < ymin2) ymin2 = v[i][1]; + else if (v[i][1] > ymax2) ymax2 = v[i][1]; + } if (v[i][2] < zmin) zmin = v[i][2]; else if (v[i][2] > zmax) zmax = v[i][2]; + if (v[i][2] > 0) + { + if (v[i][2] < zmin2) zmin2 = v[i][2]; + else if (v[i][2] > zmax2) zmax2 = v[i][2]; + } } } - else - { - xmin = ymin = zmin = Double.POSITIVE_INFINITY; - xmax = ymax = zmax = Double.NEGATIVE_INFINITY; - } - XLim.set(new double[] {xmin, xmax}, true); - YLim.set(new double[] {ymin, ymax}, true); - ZLim.set(new double[] {zmin, zmax}, true); + XLim.set(new double[] {xmin, xmax, xmin2, xmax2}, true); + YLim.set(new double[] {ymin, ymax, ymin2, ymax2}, true); + ZLim.set(new double[] {zmin, zmax, zmin2, zmax2}, true); if (FaceVertexCData.getNDims() == 1 && CDataMapping.is("scaled")) { --- NEW FILE: SimpleTextEngine.java --- /* * jhandles * * Copyright (C) 2007 Michael Goffioul * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.octave.graphics; import java.awt.*; import java.awt.image.*; import java.util.*; class SimpleTextEngine { static class SimpleFactory { private String buffer; private LinkedList list; private int anchor = 0, current = 0; SimpleFactory(String txt, LinkedList lst) { buffer = txt; list = lst; } int matchBrace(int start) { int depth = 0; while (start < buffer.length()) { switch (buffer.charAt(start)) { case '{': depth++; break; case '}': depth--; if (depth == 0) return start; default: break; } start++; } return -1; } String getArgument(int start) { if (start >= buffer.length()) return null; if (buffer.charAt(start) == '{') { int pos = matchBrace(start); if (pos < 0) return null; else { anchor = pos+1; return buffer.substring(start+1, pos); } } else { anchor = start+1; return buffer.substring(start, start+1); } } void flush() { if (current > anchor) { list.add(new Element(buffer.substring(anchor, current))); anchor = current; } } void parse() { current = anchor; while (current < buffer.length()) { switch (buffer.charAt(current)) { case '^': case '_': flush(); String arg = getArgument(current+1); if (arg != null) { if (buffer.charAt(current) == '_') list.add(new SubscriptElement(arg)); else if (buffer.charAt(current) == '^') list.add(new SuperscriptElement(arg)); current = anchor; } else current++; break; default: current++; break; } } flush(); } } static class Element { String text; Rectangle rect; Element(String txt) { text = txt; } void render(Graphics2D g) { g.drawString(text, 0, 0); } Rectangle layout(RenderCanvas comp, Font font) { FontMetrics fm = comp.getFontMetrics(font); rect = new Rectangle(0, -fm.getMaxDescent(), fm.stringWidth(text), fm.getMaxDescent()+fm.getMaxAscent()); return rect; } } static class LineElement extends Element { private LinkedList elements = new LinkedList(); LineElement(String txt) { super(txt); SimpleFactory f = new SimpleFactory(txt, elements); f.parse(); } Rectangle layout(RenderCanvas comp, Font font) { Iterator it = elements.iterator(); FontMetrics fm = comp.getFontMetrics(font); rect = new Rectangle(0, -fm.getMaxDescent(), 0, fm.getMaxAscent()+fm.getMaxDescent()); while (it.hasNext()) { Element e = (Element)it.next(); Rectangle eRect = e.layout(comp, font); eRect.x = rect.width; rect = rect.union(eRect); } return rect; } void render(Graphics2D g) { Iterator it = elements.iterator(); int xoffset = 0, yoffset = (rect.height + rect.y); g.translate(0, yoffset); while (it.hasNext()) { Element e = (Element)it.next(); e.render(g); g.translate(e.rect.width, 0); xoffset += e.rect.width; } g.translate(-xoffset, -yoffset); } void add(Element e) { elements.add(e); } } static class SubscriptElement extends LineElement { SubscriptElement(String txt) { super(txt); } Font getSubscriptFont(Font f) { return new Font(f.getFamily(), f.getStyle(), f.getSize()-2); } Rectangle layout(RenderCanvas comp, Font font) { Font subscriptFont = getSubscriptFont(font); super.layout(comp, subscriptFont); rect.y -= (rect.height+rect.y)/2; return rect; } void render(Graphics2D g) { Font currentFont = g.getFont(); Font subscriptFont = getSubscriptFont(currentFont); g.setFont(subscriptFont); super.render(g); g.setFont(currentFont); } } static class SuperscriptElement extends LineElement { SuperscriptElement(String txt) { super(txt); } Font getSuperscriptFont(Font f) { return new Font(f.getFamily(), f.getStyle(), f.getSize()-2); } Rectangle layout(RenderCanvas comp, Font font) { Font superscriptFont = getSuperscriptFont(font); super.layout(comp, superscriptFont); FontMetrics fm = comp.getFontMetrics(superscriptFont); rect.y += fm.getMaxAscent()/2; return rect; } void render(Graphics2D g) { Font currentFont = g.getFont(); FontMetrics fm = g.getFontMetrics(); int ascent = fm.getMaxAscent(); Font subscriptFont = getSuperscriptFont(currentFont); g.setFont(subscriptFont); g.translate(0, -(rect.height+rect.y)-ascent/2); super.render(g); g.translate(0, (rect.height+rect.y)+ascent/2); g.setFont(currentFont); } } static class Content extends Element { private LineElement[] lines; Content(String txt) { super(txt); String[] txtLines = txt.split("\n", -1); lines = new LineElement[txtLines.length]; for (int i=0; i<txtLines.length; i++) { lines[i] = new LineElement(txtLines[i]); } } Rectangle layout(RenderCanvas comp, Font font) { return lines[0].layout(comp, font); } void render(Graphics2D g) { lines[0].render(g); } } public static Dimension draw(RenderCanvas comp, String txt, double[] pos, int halign, int valign) { // create internal image int margin = 5; Content content = new Content(txt); Rectangle r = (Rectangle)content.layout(comp, comp.getFont()).clone(); r.width += 2*margin; r.height += 2*margin; BufferedImage img = new BufferedImage(r.width, r.height, BufferedImage.TYPE_BYTE_BINARY); // draw string Graphics g = img.getGraphics(); g.setFont(comp.getFont()); g.translate(margin, margin); content.render((Graphics2D)g); g.dispose(); com.sun.opengl.util.ImageUtil.flipImageVertically(img); // compute offsets int xoff, yoff; switch (halign) { default: case 0: xoff = 0; break; case 1: xoff = -r.width/2; break; case 2: xoff = -r.width; break; } switch (valign) { default: case 0: yoff = 0; break; case 1: yoff = -r.height/2; break; case 2: yoff = -r.height; break; } // render to canvas comp.getRenderer().drawBitmap(img, pos, xoff, yoff); // return value return new Dimension(r.width, r.height); } } Index: TextObject.java =================================================================== RCS file: /cvsroot/octave/octave-forge/extra/jhandles/src/org/octave/graphics/TextObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- TextObject.java 31 May 2007 14:44:23 -0000 1.2 +++ TextObject.java 18 Jun 2007 12:51:42 -0000 1.3 @@ -30,19 +30,12 @@ public class TextObject extends GraphicObject { - public static final int H_LEFT = 0; - public static final int H_CENTER = 1; - public static final int H_RIGHT = 2; - public static final int V_TOP = 0; - public static final int V_MIDDLE = 1; - public static final int V_BOTTOM = 3; - private Font font = null; - private Content content; + private SimpleTextEngine.Content content; private ByteBuffer data; private AffineTransform T; private Rectangle r; - private int w, h, baseline; + private int w, h; private String currentUnits; /* properties */ @@ -60,274 +53,11 @@ DoubleProperty LineWidth; DoubleProperty Margin; - class SimpleFactory - { - private String buffer; - private LinkedList list; - private int anchor = 0, current = 0; - - SimpleFactory(String txt, LinkedList lst) - { - buffer = txt; - list = lst; - } - - int matchBrace(int start) - { - int depth = 0; - while (start < buffer.length()) - { - switch (buffer.charAt(start)) - { - case '{': depth++; break; - case '}': depth--; if (depth == 0) return start; - default: break; - } - start++; - } - return -1; - } - - String getArgument(int start) - { - if (start >= buffer.length()) - return null; - if (buffer.charAt(start) == '{') - { - int pos = matchBrace(start); - if (pos < 0) - return null; - else - { - anchor = pos+1; - return buffer.substring(start+1, pos); - } - } - else - { - anchor = start+1; - return buffer.substring(start, start+1); - } - } - - void flush() - { - if (current > anchor) - { - list.add(new Element(buffer.substring(anchor, current))); - anchor = current; - } - } - - void parse() - { - current = anchor; - while (current < buffer.length()) - { - switch (buffer.charAt(current)) - { - case '^': - case '_': - flush(); - String arg = getArgument(current+1); - if (arg != null) - { - if (buffer.charAt(current) == '_') - list.add(new SubscriptElement(arg)); - else if (buffer.charAt(current) == '^') - list.add(new SuperscriptElement(arg)); - current = anchor; - } - else - current++; - break; - default: - current++; - break; - } - } - - flush(); - } - - } - - class Element - { - String text; - Rectangle rect; - - Element(String txt) - { - text = txt; - } - - void render(Graphics2D g) - { - g.drawString(text, 0, 0); - } - - Rectangle layout(RenderCanvas comp, Font font) - { - FontMetrics fm = comp.getFontMetrics(font); - rect = new Rectangle(0, -fm.getMaxDescent(), fm.stringWidth(text), fm.getMaxDescent()+fm.getMaxAscent()); - return rect; - } - } - - class LineElement extends Element - { - private LinkedList elements = new LinkedList(); - - LineElement(String txt) - { - super(txt); - - SimpleFactory f = new SimpleFactory(txt, elements); - f.parse(); - } - - Rectangle layout(RenderCanvas comp, Font font) - { - Iterator it = elements.iterator(); - FontMetrics fm = comp.getFontMetrics(font); - - rect = new Rectangle(0, -fm.getMaxDescent(), 0, fm.getMaxAscent()+fm.getMaxDescent()); - while (it.hasNext()) - { - Element e = (Element)it.next(); - Rectangle eRect = e.layout(comp, font); - eRect.x = rect.width; - rect = rect.union(eRect); - } - return rect; - } - - void render(Graphics2D g) - { - Iterator it = elements.iterator(); - int xoffset = 0, yoffset = (rect.height + rect.y); - - g.translate(0, yoffset); - while (it.hasNext()) - { - Element e = (Element)it.next(); - e.render(g); - g.translate(e.rect.width, 0); - xoffset += e.rect.width; - } - g.translate(-xoffset, -yoffset); - } - - void add(Element e) - { - elements.add(e); - } - } - - class SubscriptElement extends LineElement - { - SubscriptElement(String txt) - { - super(txt); - } - - Font getSubscriptFont(Font f) - { - return new Font(f.getFamily(), f.getStyle(), f.getSize()-2); - } - - Rectangle layout(RenderCanvas comp, Font font) - { - Font subscriptFont = getSubscriptFont(font); - - super.layout(comp, subscriptFont); - rect.y -= (rect.height+rect.y)/2; - - return rect; - } - - void render(Graphics2D g) - { - Font currentFont = g.getFont(); - Font subscriptFont = getSubscriptFont(currentFont); - - g.setFont(subscriptFont); - super.render(g); - g.setFont(currentFont); - } - } - - class SuperscriptElement extends LineElement - { - SuperscriptElement(String txt) - { - super(txt); - } - - Font getSuperscriptFont(Font f) - { - return new Font(f.getFamily(), f.getStyle(), f.getSize()-2); - } - - Rectangle layout(RenderCanvas comp, Font font) - { - Font superscriptFont = getSuperscriptFont(font); - - super.layout(comp, superscriptFont); - - FontMetrics fm = comp.getFontMetrics(superscriptFont); - rect.y += fm.getMaxAscent()/2; - - return rect; - } - - void render(Graphics2D g) - { - Font currentFont = g.getFont(); - FontMetrics fm = g.getFontMetrics(); - int ascent = fm.getMaxAscent(); - Font subscriptFont = getSuperscriptFont(currentFont); - - g.setFont(subscriptFont); - g.translate(0, -(rect.height+rect.y)-ascent/2); - super.render(g); - g.translate(0, (rect.height+rect.y)+ascent/2); - g.setFont(currentFont); - } - } - - class Content extends Element - { - private LineElement[] lines; - - Content(String txt) - { - super(txt); - String[] txtLines = txt.split("\n", -1); - lines = new LineElement[txtLines.length]; - for (int i=0; i<txtLines.length; i++) - { - lines[i] = new LineElement(txtLines[i]); - } - } - - Rectangle layout(RenderCanvas comp, Font font) - { - return lines[0].layout(comp, font); - } - - void render(Graphics2D g) - { - lines[0].render(g); - } - } - public TextObject(HandleObject parent, String txt, double[] pos) { super(parent, "text"); - this.content = new Content(txt); + this.content = new SimpleTextEngine.Content(txt); this.data = null; Rotation = new DoubleProperty(this, "Rotation", 0.0); @@ -360,6 +90,7 @@ public void validate() { super.validate(); + updateMinMax(); } public Rectangle getExtent() @@ -436,49 +167,20 @@ data = ByteBuffer.wrap(((DataBufferByte)img.getData().getDataBuffer()).getData()); } - /* TODO: remove - public void draw(GL gl) + protected void updateMinMax() { - if (data == null) - updateData(); - - AxesObject ax = getAxes(); - double[] pos = ax.convertUnits(Position.getArray(), Units.getValue()); - boolean clipEnabled = ax.getClipping(gl); - boolean dataUnits = Units.is("data"); - - int x = 0, y = 0, margin = -r.x; - - if (HAlign.is("center")) x = (r.width-2*margin)/2; - else if (HAlign.is("right")) x = (r.width-2*margin); - if (VAlign.is("bottom")) y = (r.height-2*margin); - else if (VAlign.is("middle")) y = (r.height-2*margin)/2; - else if (VAlign.is("baseline")) y = (r.height+r.y-margin); - - Point2D.Double p1 = new Point2D.Double(x, y), p2 = new Point2D.Double(); - T.transform(p1, p2); - - int xOffset = (int)p2.getX(), yOffset = h-(int)p2.getY(); + double[] p = getAxes().convertUnits(Position.getArray(), Units.getValue()); + double xmin2 = (p[0] <= 0 ? Double.POSITIVE_INFINITY : p[0]); + double xmax2 = (p[0] <= 0 ? Double.MIN_VALUE : p[0]); + double ymin2 = (p[1] <= 0 ? Double.POSITIVE_INFINITY : p[1]); + double ymax2 = (p[1] <= 0 ? Double.MIN_VALUE : p[1]); + double zmin2 = (p[2] <= 0 ? Double.POSITIVE_INFINITY : p[2]); + double zmax2 = (p[2] <= 0 ? Double.MIN_VALUE : p[2]); - TextColor.setup(gl); - if (clipEnabled) - ax.setClipping(gl, false); - gl.glEnable(GL.GL_ALPHA_TEST); - if (!dataUnits) - gl.glDisable(GL.GL_DEPTH_TEST); - gl.glAlphaFunc(GL.GL_GREATER, 0.0f); - gl.glRasterPos3d(pos[0], pos[1], pos[2]); - gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); - gl.glBitmap(0, 0, 0, 0, -xOffset, -yOffset, null, 0); - gl.glDrawPixels(w, h, GL.GL_ABGR_EXT, GL.GL_UNSIGNED_BYTE, data); - gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 4); - gl.glDisable(GL.GL_ALPHA_TEST); - if (!dataUnits) - gl.glEnable(GL.GL_DEPTH_TEST); - if (clipEnabled) - ax.setClipping(gl, true); + XLim.set(new double[] {p[0], p[0], xmin2, xmax2}, true); + YLim.set(new double[] {p[1], p[1], ymin2, ymax2}, true); + ZLim.set(new double[] {p[2], p[2], zmin2, zmax2}, true); } - */ public void draw(Renderer renderer) { @@ -515,7 +217,7 @@ } else if (p == TextString) { - content = new Content(TextString.toString()); + content = new SimpleTextEngine.Content(TextString.toString()); data = null; } else if (p == Rotation || p == TextColor || p == BackgroundColor || p == EdgeColor || @@ -524,5 +226,8 @@ if (p == Units || p == Position) PositionMode.set(new Boolean(false)); + + if (p == Position) + updateMinMax(); } } |