package org.geogebra.common.geogebra3D.euclidian3D.openGL; import org.geogebra.common.awt.GColor; import org.geogebra.common.euclidian.draw.DrawVector; import org.geogebra.common.euclidian.plot.CurvePlotter.Gap; import org.geogebra.common.euclidian.plot.PathPlotter; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.kernel.SegmentType; import org.geogebra.common.kernel.Matrix.CoordSys; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.Feature; /** * 3D brush, drawing circular-section curves. * * @author mathieu * */ public class PlotterBrush implements PathPlotter { /** thickness for drawing 3D lines */ public static final float LINE3D_THICKNESS = 0.5f; /** manager */ protected Manager manager; /** index */ private int index; /** start and end sections */ protected PlotterBrushSection start; /** start and end sections */ protected PlotterBrushSection end; private boolean justStarted = false; private boolean notStarted = false; /** current thickness */ private float thickness; private int lineThickness; /** view scale */ private float scale; /** global length of the curve */ protected float length; // color /** color r, g, b, a */ private float red, green, blue, alpha; /** says if it's colored */ private boolean hasColor; // texture /** start and end textures values */ private float texturePosZero, textureValZero; /** textures coords */ private float[] textureX = new float[2]; /** type of texture */ static final public int TEXTURE_CONSTANT_0 = 0; static final private int TEXTURE_ID = 1; protected static final int TEXTURE_AFFINE = 2; static final private int TEXTURE_LINEAR = 3; private int textureTypeX = TEXTURE_ID; static final private float TEXTURE_AFFINE_FACTOR = 0.05f; /** curve position (for texture) */ private float curvePos; // arrows /** no arrows */ static final public int ARROW_TYPE_NONE = 0; /** simple arrows */ static final public int ARROW_TYPE_SIMPLE = 1; /** closed segment */ static final public int ARROW_TYPE_CLOSED = 2; private int arrowType = ARROW_TYPE_NONE; /** length of the arrow */ static private float ARROW_LENGTH = 3f; /** width of the arrow */ static private float ARROW_WIDTH = ARROW_LENGTH / 4f; // /** length of the arrow */ // static private float ARROW_HANDLE_LENGTH = ARROW_LENGTH;//ARROW_WIDTH; /** ticks */ static public enum Ticks { NONE, MAJOR, MAJOR_AND_MINOR } /** has ticks ? */ private Ticks ticks = Ticks.NONE; /** distance between two ticks */ private float ticksDistance; /** * offset for origin of the ticks (0: start of the curve, 1: end of the * curve) */ private float ticksOffset; // level of detail /** number of rules */ protected final static int LATITUDES = 8; /** * pre-calculated cosinus */ final static double[] COSINUS = new double[LATITUDES + 1]; /** * pre-calculated sinus */ final static double[] SINUS = new double[LATITUDES + 1]; static { for (int i = 0; i <= LATITUDES; i++) { COSINUS[i] = Math.cos(2 * i * Math.PI / LATITUDES); SINUS[i] = Math.sin(2 * i * Math.PI / LATITUDES); } } /** * default constructor * * @param manager */ public PlotterBrush(Manager manager) { this.manager = manager; start = new PlotterBrushSection(manager); end = new PlotterBrushSection(manager); } // ////////////////////////////////// // START AND END // ////////////////////////////////// /** * start new curve */ public void start(int old) { index = manager.startNewList(old); hasColor = false; notStarted = true; } /** * end curve * * @return gl index of the curve */ public int end() { manager.endList(); return index; } // ////////////////////////////////// // SIMPLE DRAWING METHODS // ////////////////////////////////// /** * start new curve part * * @param point */ public void down(Coords point) { start.set(point, thickness); justStarted = true; notStarted = false; } /** * start new curve part * * @param point */ private void down(Coords point, Coords clockU, Coords clockV) { start.set(point, thickness, clockU, clockV); justStarted = true; } /** * move to point and draw curve part * * @param point */ public void moveTo(Coords point) { // update start and end sections if (justStarted) { end.set(start, point, thickness, true); justStarted = false; } else { PlotterBrushSection tmp = start; start = end; end = tmp; end.set(start, point, thickness, false); } join(); } /** * move to new coords only if not equal to last. Set texture pos. * * @param point * coords */ public void curveTo(Coords point) { if (notStarted) { notStarted = false; setCurvePos(0); down(point); return; } if (start.centerEqualsForKernel(point)) { return; } // update start and end sections if (justStarted) { justStarted = false; } else { PlotterBrushSection tmp = start; start = end; end = tmp; } end.set(start, point, thickness); // set curve pos addCurvePos((float) end.length); join(); } /** * move to point and draw curve part * * @param point */ private void moveTo(Coords point, Coords clockU, Coords clockV) { if (justStarted) { justStarted = false; } else { PlotterBrushSection tmp = start; start = end; end = tmp; } end.set(point, thickness, clockU, clockV); join(); } /** * join start to end */ public void join() { // draw curve part manager.startGeometry(Manager.Type.TRIANGLE_STRIP); double u, v; for (int i = 0; i <= LATITUDES; i++) { u = SINUS[i]; v = COSINUS[i]; draw(start, u, v, 0); // bottom of the tube rule draw(end, u, v, 1); // top of the tube rule } manager.endGeometry(); } private Coords drawNormal = new Coords(3), drawPos = new Coords(3); /** * draws a section point * */ protected void draw(PlotterBrushSection s, double u, double v, int texture) { s.getNormalAndPosition(u, v, drawNormal, drawPos); // set normal manager.normalToScale(drawNormal); // set texture float pos = textureX[texture]; switch (textureTypeX) { case TEXTURE_ID: default: manager.texture(pos, 0); break; case TEXTURE_CONSTANT_0: manager.texture(0, 0); break; case TEXTURE_AFFINE: // float factor = (int) (TEXTURE_AFFINE_FACTOR*length*scale); //TODO // integer for cycles float factor; if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { factor = TEXTURE_AFFINE_FACTOR * length; } else { factor = TEXTURE_AFFINE_FACTOR * length * scale; } manager.texture(factor * (pos - texturePosZero) + textureValZero, 0); break; case TEXTURE_LINEAR: if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { manager.texture(TEXTURE_AFFINE_FACTOR * pos, 0); } else { manager.texture(TEXTURE_AFFINE_FACTOR * scale * pos, 0); } break; } // set vertex vertex(drawPos); } private void vertex(Coords v) { // set color if (hasColor) { manager.color(red, green, blue, alpha); } // set vertex manager.vertex(v); } // ////////////////////////////////// // GEOMETRY DRAWING METHODS // ////////////////////////////////// private float lengthInScene; /** * segment curve * * @param p1 * @param p2 */ public void segment(Coords p1, Coords p2) { if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { tmpCoords.setSub(p2, p1); length = getNormInScreenCoords(tmpCoords); lengthInScene = (float) p1.distance(p2); } else { length = (float) p1.distance(p2); lengthInScene = length; } if (Kernel.isEqual(length, 0, Kernel.STANDARD_PRECISION)) { return; } down(p1); float factor, arrowPos; switch (arrowType) { case ARROW_TYPE_NONE: default: setTextureX(0, 1); moveTo(p2); break; case ARROW_TYPE_SIMPLE: if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { factor = (float) (DrawVector.getFactor(lineThickness) * LINE3D_THICKNESS * lengthInScene / length); } else { factor = (float) (DrawVector.getFactor(lineThickness) * LINE3D_THICKNESS / scale); } if (ARROW_LENGTH * factor > 0.9f * lengthInScene) { factor = 0.9f * lengthInScene / ARROW_LENGTH; } arrowPos = ARROW_LENGTH / lengthInScene * factor; tmpCoords3.setAdd(tmpCoords4.setMul(p1, arrowPos), tmpCoords3.setMul(p2, 1 - arrowPos)); setTextureX(0); if (ticksDistance > 0) { switch (ticks) { case MAJOR: default: tmpCoords4.setSub(p2, p1); tmpCoords4.normalize(); float thicknessOld = this.thickness; float ticksDistanceNormed = ticksDistance / lengthInScene; float i = ticksOffset - ((int) (ticksOffset / ticksDistanceNormed)) * ticksDistanceNormed; float ticksDelta = thicknessOld; if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { ticksDelta *= lengthInScene / length; } float ticksThickness = 4 * thicknessOld; if (i * lengthInScene <= ticksDelta) { i += ticksDistanceNormed; } for (; i <= 1 - arrowPos; i += ticksDistanceNormed) { double x = i * lengthInScene; tmpCoords.setAdd(p1, tmpCoords.setMul(tmpCoords4, x - ticksDelta)); tmpCoords2.setAdd(p1, tmpCoords2.setMul(tmpCoords4, x + ticksDelta)); drawTick(tmpCoords, tmpCoords2, i, ticksThickness, thicknessOld); } break; case MAJOR_AND_MINOR: tmpCoords4.setSub(p2, p1); tmpCoords4.normalize(); thicknessOld = this.thickness; ticksDistanceNormed = ticksDistance / lengthInScene; i = ticksOffset - ((int) (ticksOffset / ticksDistanceNormed)) * ticksDistanceNormed; if (i < 0) { i += ticksDistanceNormed; } ticksDelta = thicknessOld; if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { ticksDelta *= lengthInScene / length; } ticksThickness = 4 * thicknessOld; float ticksMinorThickness = 2.5f * thicknessOld; boolean minor = false; if (i > ticksDistanceNormed / 2 + ticksDelta / lengthInScene) { minor = true; i -= ticksDistanceNormed / 2; } else if (i * lengthInScene <= ticksDelta) { i += ticksDistanceNormed / 2; minor = true; } for (; i <= 1 - arrowPos; i += ticksDistanceNormed / 2) { double x = i * lengthInScene; tmpCoords.setAdd(p1, tmpCoords.setMul(tmpCoords4, x - ticksDelta)); tmpCoords2.setAdd(p1, tmpCoords2.setMul(tmpCoords4, x + ticksDelta)); drawTick(tmpCoords, tmpCoords2, i, minor ? ticksMinorThickness : ticksThickness, thicknessOld); minor = !minor; } break; case NONE: break; } } drawArrowBase(arrowPos, tmpCoords3); textureTypeX = TEXTURE_ID; setTextureX(0, 0); if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { setThickness(factor * ARROW_WIDTH * length / lengthInScene); } else { setThickness(factor * ARROW_WIDTH); } moveTo(tmpCoords3); setThickness(0); moveTo(p2); break; } if (arrowType == ARROW_TYPE_CLOSED) { setThickness(0); moveTo(p2); } } /** * draw a tick * * @param p1b * @param p2b * @param i * @param ticksThickness * @param thicknessOld */ protected void drawTick(Coords p1b, Coords p2b, float i, float ticksThickness, float thicknessOld) { setTextureType(TEXTURE_AFFINE); setTextureX(i); moveTo(p1b); setThickness(ticksThickness); setTextureType(TEXTURE_CONSTANT_0); moveTo(p1b); moveTo(p2b); setThickness(thicknessOld); moveTo(p2b); } /** * draw arrow base * * @param arrowPos * @param arrowBase */ protected void drawArrowBase(float arrowPos, Coords arrowBase) { setTextureType(TEXTURE_AFFINE); setTextureX(1 - arrowPos); moveTo(arrowBase); } /** * draws a circle * * @param center * @param v1 * @param v2 * @param radius * @param longitude */ public void circle(Coords center, Coords v1, Coords v2, double radius, int longitude) { arc(center, v1, v2, radius, 0, 2 * Math.PI, longitude); } /** * * @param radius * radius of the arc * @param halfExtent * arc half extent * @param viewScale * view scale * @return longitude length needed to render the arc */ public int calcArcLongitudesNeeded(double radius, double halfExtent, double viewScale) { int longitude; double size = radius * halfExtent * viewScale; if (size > 262144) { // longitude would be > 1024 longitude = manager.getLongitudeMax(); } else { longitude = 8; while (longitude * longitude <= 4 * size && longitude < manager.getLongitudeMax()) {// find the // correct // longitude // size longitude *= 2; } } // Log.debug("circle ==== longitude="+longitude); return longitude; } /** * draw an arc * * @param center * @param v1 * @param v2 * @param radius * @param arcStart * @param extent */ public void arc(Coords center, Coords v1, Coords v2, double radius, double arcStart, double extent, int longitude) { length = (float) (extent * radius); vn2.setCrossProduct(v2, v1); float dt = (float) 1 / longitude; float da = (float) (extent * dt); float u, v; u = (float) Math.cos(arcStart); v = (float) Math.sin(arcStart); setTextureX(0, 0); vn1.setAdd(tmpCoords.setMul(v1, u), vn1.setMul(v2, v)); tmpCoords.setAdd(center, tmpCoords.setMul(vn1, radius)); down(tmpCoords, vn1, vn2); for (int i = 1; i <= longitude; i++) { u = (float) Math.cos(arcStart + i * da); v = (float) Math.sin(arcStart + i * da); setTextureX(i * dt); vn1.setAdd(tmpCoords.setMul(v1, u), vn1.setMul(v2, v)); tmpCoords.setAdd(center, tmpCoords.setMul(vn1, radius)); moveTo(tmpCoords, vn1, vn2); } } /** * draw an arc extended with arrows * * @param center * @param v1 * @param v2 * @param radius * @param arcStart * @param extent * @param longitude */ public void arcExtendedWithArrows(Coords center, Coords v1, Coords v2, double radius, double arcStart, double extent, int longitude) { length = (float) (extent * radius); float oldThickness = getThickness(); double arrowLength = oldThickness * 5; vn2.setCrossProduct(v2, v1); float dt = (float) 1 / longitude; float da = (float) (extent * dt); float u, v; // start arrow u = (float) Math.cos(arcStart); v = (float) Math.sin(arcStart); vn1.setAdd(tmpCoords.setMul(v1, u), vn1.setMul(v2, v)); tmpCoords.setAdd(center, tmpCoords.setMul(vn1, radius)); tmpCoords3.setCrossProduct(vn2, vn1); tmpCoords2.setAdd(tmpCoords, tmpCoords3.mulInside(arrowLength)); setThickness(0); setTextureX(0, 0); down(tmpCoords2, vn1, vn2); setThickness(2 * oldThickness); setTextureX(0, 0); moveTo(tmpCoords, vn1, vn2); setThickness(oldThickness); setTextureX(0, 0); moveTo(tmpCoords, vn1, vn2); // arc for (int i = 1; i <= longitude; i++) { u = (float) Math.cos(arcStart + i * da); v = (float) Math.sin(arcStart + i * da); setTextureX(i * dt); vn1.setAdd(tmpCoords.setMul(v1, u), vn1.setMul(v2, v)); tmpCoords.setAdd(center, tmpCoords.setMul(vn1, radius)); moveTo(tmpCoords, vn1, vn2); } // end arrow setThickness(2 * oldThickness); setTextureX(0, 0); moveTo(tmpCoords, vn1, vn2); tmpCoords3.setCrossProduct(vn1, vn2); tmpCoords2.setAdd(tmpCoords, tmpCoords3.mulInside(arrowLength)); setThickness(0); setTextureX(0, 0); moveTo(tmpCoords2, vn1, vn2); // back to old thickness setThickness(oldThickness); } private Coords m = new Coords(3), vn1 = new Coords(3); private Coords tmpCoords = new Coords(3), tmpCoords2 = new Coords(3), tmpCoords3 = new Coords(3), tmpCoords4 = new Coords(3); private Coords f1 = new Coords(4), f2 = new Coords(4), vn2 = new Coords(3); /** * draws an ellipse * * @param center * @param v1 * 1st eigenvector * @param v2 * 2nd eigenvector * @param a * 1st eigenvalue * @param b * 2nd eigenvalue */ public void arcEllipse(Coords center, Coords v1, Coords v2, double a, double b, double arcStart, double extent) { // Ramanujan approximation // length=(float) (Math.PI*(3*(a+b)-Math.sqrt((3*a+b)*(a+3*b)))); //TODO // use integer to avoid bad dash cycle connection length = 1; setCurvePos(0); setTextureType(PlotterBrush.TEXTURE_LINEAR); // foci double f = Math.sqrt(a * a - b * b); f1.setMul(v1, f); f2.setMul(v1, -f); int longitude = manager.getLongitudeDefault(); vn2.setCrossProduct(v2, v1); float dt = (float) 1 / longitude; float da = (float) (extent * dt); float u, v; u = (float) Math.cos(arcStart); v = (float) Math.sin(arcStart); m.setAdd(m.setMul(v1, a * u), tmpCoords.setMul(v2, b * v)); vn1.setAdd(tmpCoords3.setSub(m, f1).normalize(), tmpCoords4.setSub(m, f2).normalize()).normalize(); tmpCoords.setAdd(center, m); down(tmpCoords, vn1, vn2); for (int i = 1; i <= longitude; i++) { u = (float) Math.cos(arcStart + i * da); v = (float) Math.sin(arcStart + i * da); tmpCoords2.set(m); m.setAdd(m.setMul(v1, a * u), tmpCoords.setMul(v2, b * v)); addCurvePos(tmpCoords2.setSub(m, tmpCoords2)); vn1.setAdd(tmpCoords3.setSub(m, f1).normalize(), tmpCoords4.setSub(m, f2).normalize()).normalize(); tmpCoords.setAdd(center, m); moveTo(tmpCoords, vn1, vn2); } } private void addCurvePos(Coords coords) { if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { addCurvePos(getNormInScreenCoords(coords)); } else { addCurvePos((float) coords.norm()); } } private float getNormInScreenCoords(Coords coords) { manager.scaleXYZ(coords); coords.calcNorm(); return (float) coords.getNorm(); } /** * draws quarter of an hyperbola * * @param center * center * @param v1 * 1st eigenvector * @param v2 * 2nd eigenvector * @param a * 1st eigenvalue * @param b * 2nd eigenvalue * @param tMin * t min * @param tMax * t max */ public void hyperbolaBranch(Coords center, Coords v1, Coords v2, double a, double b, double tMin, double tMax) { // foci double f = Math.sqrt(a * a + b * b); f1.setMul(v1, f); f2.setMul(v1, -f); // dash length = 1; setTextureType(PlotterBrush.TEXTURE_LINEAR); setCurvePos(0.75f / (TEXTURE_AFFINE_FACTOR * scale)); // midpoint is // middle of an // empty dash int longitude = manager.getLongitudeDefault(); vn2.setCrossProduct(v1, v2); float dt = (float) (tMax - tMin) / longitude; float u, v; u = (float) Math.cosh(tMin); v = (float) Math.sinh(tMin); m.setAdd(m.setMul(v1, a * u), tmpCoords.setMul(v2, b * v)); vn1.setSub(tmpCoords3.setSub(m, f1).normalize(), tmpCoords4.setSub(m, f2).normalize()).normalize(); tmpCoords.setAdd(center, m); down(tmpCoords, vn1, vn2); for (int i = 1; i <= longitude; i++) { u = (float) Math.cosh(tMin + i * dt); v = (float) Math.sinh(tMin + i * dt); tmpCoords2.set(m); m.setAdd(m.setMul(v1, a * u), tmpCoords.setMul(v2, b * v)); addCurvePos(tmpCoords2.setSub(m, tmpCoords2)); vn1.setSub(tmpCoords3.setSub(m, f1).normalize(), tmpCoords4.setSub(m, f2).normalize()).normalize(); tmpCoords.setAdd(center, m); moveTo(tmpCoords, vn1, vn2); } } /** * draws a parabola, and save ends coords in p1, p2 (if not null) * * @param center * center * @param v1 * 1st eigenvector * @param v2 * 2nd eigenvector * @param p * eigenvalue * @param tMin * t min * @param tMax * t max * @param p1 * to store start point * @param p2 * to store end point */ public void parabola(Coords center, Coords v1, Coords v2, double p, double tMin, double tMax, Coords p1, Coords p2) { // focus f1.setMul(v1, p / 2); vn2.setCrossProduct(v1, v2); int longitude = manager.getLongitudeDefault(); // dash length = 1; setTextureType(PlotterBrush.TEXTURE_LINEAR); setCurvePos(0.75f / (TEXTURE_AFFINE_FACTOR * scale)); float dt = (float) (tMax - tMin) / longitude; float u, v; double t; t = tMin; u = (float) (p * t * t / 2); v = (float) (p * t); m.setAdd(m.setMul(v1, u), tmpCoords.setMul(v2, v)); vn1.setSub(tmpCoords3.setSub(m, f1).normalize(), v1).normalize(); tmpCoords.setAdd(center, m); down(tmpCoords, vn1, vn2); if (p1 != null) { p1.set(tmpCoords); } for (int i = 1; i <= longitude; i++) { t = tMin + i * dt; u = (float) (p * t * t / 2); v = (float) (p * t); tmpCoords2.set(m); m.setAdd(m.setMul(v1, u), tmpCoords.setMul(v2, v)); addCurvePos(tmpCoords2.setSub(m, tmpCoords2)); vn1.setSub(tmpCoords3.setSub(m, f1).normalize(), v1).normalize(); tmpCoords.setAdd(center, m); moveTo(tmpCoords, vn1, vn2); } if (p2 != null) { p2.set(tmpCoords); } } // ////////////////////////////////// // THICKNESS // ////////////////////////////////// /** * set the current thickness of the brush, using integer for thickness (see * {@link GeoElement#getLineThickness()} * * @param thickness * @param scale * @return real world thickness */ public float setThickness(int thickness, float scale) { this.lineThickness = thickness; this.scale = scale; float t; if (manager.getView3D().getApplication() .has(Feature.DIFFERENT_AXIS_RATIO_3D)) { t = lineThickness * LINE3D_THICKNESS; } else { t = lineThickness * LINE3D_THICKNESS / scale; } setThickness(t); return t; } /** * set the current thickness of the brush * * @param thickness */ public void setThickness(float thickness) { this.thickness = thickness; } /** * * @return current thickness of the brush */ public float getThickness() { return thickness; } // ////////////////////////////////// // COLOR // ////////////////////////////////// /** * sets the current color * * @param color * @param alpha */ public void setColor(GColor color, float alpha) { this.red = color.getRed() / 255f; this.green = color.getGreen() / 255f; this.blue = color.getBlue() / 255f; this.alpha = alpha; hasColor = true; } /** * sets the current color (alpha set to 1) * * @param color */ public void setColor(GColor color) { setColor(color, 1); } // ////////////////////////////////// // TEXTURE // ////////////////////////////////// /** * sets the position of the point on the curve and sets the texture x * * @param pos * */ public void setCurvePos(float pos) { curvePos = pos; setTextureX(pos); } /** * add the distance to the position on the curve (used for texture) * * @param distance * */ public void addCurvePos(float distance) { setCurvePos(curvePos + distance); } /** * set affine texture zero position * * @param posZero * position of the "center" of the cylinder * @param valZero * texture coord for the "center" */ public void setAffineTexture(float posZero, float valZero) { texturePosZero = posZero; textureValZero = valZero; setTextureType(TEXTURE_AFFINE); } /** * */ public void setPlainTexture() { setTextureType(TEXTURE_CONSTANT_0); } /** * sets the type of texture * * @param type */ protected void setTextureType(int type) { textureTypeX = type; } private void setTextureX(float x0, float x1) { this.textureX[0] = x0; this.textureX[1] = x1; } protected void setTextureX(float x) { setTextureX(textureX[1], x); } // ////////////////////////////////// // ARROWS // ////////////////////////////////// /** * sets the type of arrow used by the pencil. * * @param arrowType * type of arrow, see {@link #ARROW_TYPE_NONE}, * {@link #ARROW_TYPE_SIMPLE}, ... */ public void setArrowType(int arrowType) { this.arrowType = arrowType; } // ////////////////////////////////// // TICKS // ////////////////////////////////// /** * sets the type of arrow used by the pencil. * * @param ticks */ public void setTicks(Ticks ticks) { this.ticks = ticks; } /** * sets the distance between two ticks * * @param distance */ public void setTicksDistance(float distance) { this.ticksDistance = distance; } /** * sets the offset for origin of the ticks (0: start of the curve, 1: end of * the curve) * * @param offset */ public void setTicksOffset(float offset) { this.ticksOffset = offset; } // ////////////////////////////// // PATH PLOTTER // ////////////////////////////// private Coords tmpDrawTo = Coords.createInhomCoorsInD3(); @Override public void drawTo(double[] pos, SegmentType lineTo) { tmpDrawTo.set(pos); drawTo(lineTo == SegmentType.LINE_TO); } public void drawTo(double x, double y, double z, boolean lineTo) { tmpDrawTo.setX(x); tmpDrawTo.setY(y); tmpDrawTo.setZ(z); drawTo(lineTo); } private void drawTo(boolean lineTo) { // Log.debug("\n"+p); if (lineTo) { curveTo(tmpDrawTo); } else { setCurvePos(0); down(tmpDrawTo); } } @Override public void lineTo(double[] pos) { drawTo(pos, SegmentType.LINE_TO); } @Override public void moveTo(double[] pos) { tmpDrawTo.set(pos); if (pos.length == 2) { // in case of 2D point tmpDrawTo.setZ(0); } drawTo(false); } public void moveTo(double x, double y, double z) { drawTo(x, y, z, false); } @Override public void corner() { // TODO Auto-generated method stub } @Override public void corner(double[] pos) { // TODO Auto-generated method stub } @Override public void firstPoint(double[] pos, Gap moveToAllowed) { // TODO only Gap.MOVE_TO implemented moveTo(pos); } @Override public double[] newDoubleArray() { return new double[3]; } private Coords tmpCopyCoords; @Override public boolean copyCoords(MyPoint point, double[] ret, CoordSys transformSys) { ret[0] = point.x; ret[1] = point.y; ret[2] = point.getZ();// maybe 0 if 2D point if (transformSys != CoordSys.XOY) { if (tmpCopyCoords == null) { tmpCopyCoords = Coords.createInhomCoorsInD3(); } transformSys.getPointFromOriginVectors(ret[0], ret[1], tmpCopyCoords); ret[0] = tmpCopyCoords.getX(); ret[1] = tmpCopyCoords.getY(); ret[2] = tmpCopyCoords.getZ(); } return true; } /** * set the length for texture pos * * @param length * length */ public void setLength(float length) { this.length = length; } @Override public void endPlot() { // TODO Auto-generated method stub } @Override public boolean supports(CoordSys transformSys) { return true; } }