package org.geogebra.common.geogebra3D.euclidian3D.draw; import java.util.TreeMap; import org.geogebra.common.euclidian.DrawAxis; import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D; import org.geogebra.common.geogebra3D.euclidian3D.Hits3D; import org.geogebra.common.geogebra3D.euclidian3D.Hitting; import org.geogebra.common.geogebra3D.euclidian3D.openGL.PlotterBrush; import org.geogebra.common.geogebra3D.euclidian3D.openGL.PlotterBrush.Ticks; import org.geogebra.common.geogebra3D.euclidian3D.openGL.Renderer; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.kernelND.GeoAxisND; import org.geogebra.common.util.debug.Log; /** * Class for drawing axis (Ox), (Oy), ... * * @author matthieu * */ public class DrawAxis3D extends DrawLine3D { private TreeMap<String, DrawLabel3D> labels; /** * common constructor * * @param view3D * view * @param axis3D * axis */ public DrawAxis3D(EuclidianView3D view3D, GeoAxisND axis3D) { super(view3D, axis3D); super.setDrawMinMax(-2, 2); labels = new TreeMap<String, DrawLabel3D>(); } /** * drawLabel is used here for ticks */ @Override public void drawLabel(Renderer renderer) { // Application.debug(getGeoElement()+": // "+getGeoElement().isLabelVisible()); if (!getGeoElement().isEuclidianVisible()) { return; } if (!getGeoElement().isLabelVisible()) { return; } for (DrawLabel3D currentLabel : labels.values()) { currentLabel.draw(renderer); } super.drawLabel(renderer); } @Override public void setWaitForReset() { super.setWaitForReset(); for (DrawLabel3D currentLabel : labels.values()) { currentLabel.setWaitForReset(); } } @Override protected void updateLabel() { // draw numbers GeoAxisND axis = (GeoAxisND) getGeoElement(); int axisIndex = axis.getType(); double distance = getView3D().getAxisNumberingDistance(axisIndex); // Application.debug("drawMinMax="+getDrawMin()+","+getDrawMax()); double[] minmax = getDrawMinMax(); int iMin = (int) (minmax[0] / distance); int iMax = (int) (minmax[1] / distance); if (minmax[0] > 0) { iMin++; } else if (minmax[1] < 0) { iMax--; } int nb = iMax - iMin + 1; // Application.debug("iMinMax="+iMin+","+iMax); if (nb < 1) { Log.debug("nb=" + nb); // labels = null; return; } // sets all already existing labels not visible for (DrawLabel3D currentLabel : labels.values()) { currentLabel.setIsVisible(false); } if (getView3D().getShowAxisNumbers(axisIndex)) { String unitLabel = getView3D().getAxisUnitLabel(axisIndex); if (getView3D().getPiAxisUnit(axisIndex)) { unitLabel = null; } for (int i = iMin; i <= iMax; i++) { double val = i * distance; Coords origin = ((GeoAxisND) getGeoElement()).getPointInD(3, val); // draw numbers String strNum = DrawAxis.tickDescription(getView3D(), i, axisIndex); if (unitLabel != null) { strNum += unitLabel; } // check if the label already exists DrawLabel3D tickLabel = labels.get(strNum); if (tickLabel != null) { // sets the label visible tickLabel.setIsVisible(true); tickLabel.update(strNum, getView3D().getFontAxes(), getGeoElement().getObjectColor(), origin.copyVector(), numbersXOffset, numbersYOffset); tickLabel.updatePosition(getView3D().getRenderer()); // TODO optimize this } else { // creates new label tickLabel = new DrawLabel3D(getView3D(), this); tickLabel.setAnchor(true); tickLabel.update(strNum, getView3D().getFontAxes(), getGeoElement().getObjectColor(), origin.copyVector(), numbersXOffset, numbersYOffset); tickLabel.updatePosition(getView3D().getRenderer()); labels.put(strNum, tickLabel); } } } // update end of axis label String text = getView3D().getAxisLabel(axisIndex); if (text == null || text.length() == 0) { label.setIsVisible(false); } else { label.setAnchor(true); label.update(text, getView3D().getAxisLabelFont(axisIndex), getGeoElement().getObjectColor(), ((GeoAxisND) getGeoElement()).getPointInD(3, minmax[1]), getGeoElement().labelOffsetX, // -4, getGeoElement().labelOffsetY// -6 ); label.updatePosition(getView3D().getRenderer()); } } @Override public void setLabelWaitForReset() { super.setLabelWaitForReset(); for (DrawLabel3D l : labels.values()) { l.setWaitForReset(); } } @Override protected void updateLabelPosition() { // nothing to do here } @Override protected boolean updateForItSelf() { setLabelWaitForUpdate(); double[] minmax = getDrawMinMax(); int axisIndex = ((GeoAxisND) getGeoElement()).getType(); PlotterBrush brush = getView3D().getRenderer().getGeometryManager() .getBrush(); brush.setArrowType(PlotterBrush.ARROW_TYPE_SIMPLE); switch (getView3D().getAxisTickStyle(axisIndex)) { case 0: default: brush.setTicks(Ticks.MAJOR_AND_MINOR); break; case 1: brush.setTicks(Ticks.MAJOR); break; case 2: brush.setTicks(Ticks.NONE); break; } brush.setTicksDistance( (float) getView3D().getAxisNumberingDistance(axisIndex)); brush.setTicksOffset((float) (-minmax[0] / (minmax[1] - minmax[0]))); super.updateForItSelf(false); brush.setArrowType(PlotterBrush.ARROW_TYPE_NONE); brush.setTicks(Ticks.NONE); return true; } @Override protected double getScale() { return getView3D() .getScale(((GeoAxisND) getGeoElement()).getType()); } @Override protected void setAffineTexture(PlotterBrush brush, double[] minmax) { brush.setAffineTexture(0f, 0f); } private int numbersXOffset, numbersYOffset; /** * update values for ticks and labels */ public void updateDecorations() { // update decorations GeoAxisND axis = (GeoAxisND) getGeoElement(); // gets the direction vector of the axis as it is drawn on screen Coords v = new Coords(4); v.setMul(getView3D().getToScreenMatrixForGL(), axis.getDirectionInD3()); v.set(3, 0); // set z-coord to 0 // calc orthogonal offsets int vx = (int) getView3D().unscale(v.get(1) * 1.5 * axis.getTickSize()); int vy = (int) getView3D().unscale(v.get(2) * 1.5 * axis.getTickSize()); numbersXOffset = -vy; numbersYOffset = vx; // if (yOffset>0){ if (axis.getType() == GeoAxisND.X_AXIS) { numbersXOffset = -numbersXOffset; numbersYOffset = -numbersYOffset; } getGeoElement().setLabelOffset(((-vx - numbersXOffset) * 3) / 2, // -vx,//-2*xOffset, ((-vy - numbersYOffset) * 3) / 2// -vy//-2*yOffset ); } /** * @return distance between two ticks */ public double getNumbersDistance() { return 1;// ((GeoAxisND) getGeoElement()).getNumbersDistance(); } @Override protected void updateForView() { // done in 3D view } private boolean outsideBox = false; /** * sets the min/max for drawing immediately * * @param minMax * x,y,z min/max */ public void setDrawMinMaxImmediatly(double[][] minMax) { int type = ((GeoAxisND) getGeoElement()).getType(); double min = minMax[type][0]; double max = minMax[type][1]; outsideBox = false; if (getView3D().getPositiveAxis(type)) { if (min < 0) { if (max > 0) { min = 0; } else { outsideBox = true; } } } if (!outsideBox) { // check if outside the box switch (type) { default: case GeoAxisND.X_AXIS: outsideBox = (minMax[GeoAxisND.Y_AXIS][0] * minMax[GeoAxisND.Y_AXIS][1] > 0) || (minMax[GeoAxisND.Z_AXIS][0] * minMax[GeoAxisND.Z_AXIS][1] > 0); break; case GeoAxisND.Y_AXIS: outsideBox = (minMax[GeoAxisND.Z_AXIS][0] * minMax[GeoAxisND.Z_AXIS][1] > 0) || (minMax[GeoAxisND.X_AXIS][0] * minMax[GeoAxisND.X_AXIS][1] > 0); break; case GeoAxisND.Z_AXIS: outsideBox = (minMax[GeoAxisND.X_AXIS][0] * minMax[GeoAxisND.X_AXIS][1] > 0) || (minMax[GeoAxisND.Y_AXIS][0] * minMax[GeoAxisND.Y_AXIS][1] > 0); break; } } // if outside the box, set all labels invisible if (outsideBox) { for (DrawLabel3D currentLabel : labels.values()) { currentLabel.setIsVisible(false); } } super.setDrawMinMax(min, max); } @Override final protected boolean isVisible() { return (!outsideBox) && super.isVisible(); } @Override protected boolean hitLabel(Hitting hitting, Hits3D hits) { return false; // no label to hit } @Override public boolean hasPickableLable() { return false; } }