package org.geogebra.common.geogebra3D.euclidian3D.openGL; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.Matrix.Coords; /** * class describing the section of the brush * * @author mathieu * */ public class PlotterBrushSection { private Manager manager; /** center and clock vectors */ private Coords center; private Coords clockU; private Coords clockV; /** direction from last point */ private Coords direction; double length; /** normal (for caps) */ private Coords normal = null; /** normal deviation along direction */ private double normalDevD = 0; private double normalDevN = 1; /** thickness = radius of the section */ private float thickness; /** * constructor * * @param manager * geometry manager */ public PlotterBrushSection(Manager manager) { this.manager = manager; center = Coords.createInhomCoorsInD3(); clockU = new Coords(4); clockU.setUndefined(); clockV = new Coords(4); clockV.setUndefined(); direction = new Coords(4); direction.setUndefined(); normal = new Coords(4); normal.setUndefined(); normalDevD = 0; } private void setCenter(Coords point) { center.set(point); manager.scaleXYZ(center); } /** * * @param point * point * @return true if section center is equal to point with Kernel standard * precision */ public boolean centerEqualsForKernel(Coords point) { return point.equalsForKernel(center, Kernel.STANDARD_PRECISION); } public void set(Coords point, float thickness, Coords clockU, Coords clockV) { setCenter(point); this.thickness = thickness; this.clockU.set(clockU); this.clockV.set(clockV); direction.setUndefined(); normal.setUndefined(); normalDevD = 0; } public void set(Coords point, float thickness) { setCenter(point); this.thickness = thickness; clockU.setUndefined(); clockV.setUndefined(); direction.setUndefined(); normal.setUndefined(); normalDevD = 0; } public void set(PlotterBrushSection s, Coords point, float thickness, boolean updateClock) { setCenter(point); this.thickness = thickness; direction.setSub(center, s.center); if (center.equalsForKernel(s.center, Kernel.STANDARD_PRECISION)) { if (this.thickness < s.thickness) { normal.set(s.direction); } else { normal.setMul(s.direction, -1); } s.normal.set(normal); // keep last direction direction.set(s.direction); normalDevD = 0; } else { // calc normal deviation double dt = this.thickness - s.thickness; if (dt != 0) { direction.calcNorm(); double l = direction.getNorm(); double h = Math.sqrt(l * l + dt * dt); normalDevD = -dt / h; normalDevN = l / h; // normalDevD = 0.0000; normalDevN = 1; s.normalDevD = normalDevD; s.normalDevN = normalDevN; // Application.debug("dt="+dt+",normalDev="+normalDevD+","+normalDevN); } else { normalDevD = 0; } direction.normalize(); s.direction.set(direction); normal.setUndefined(); s.normal.setUndefined(); // calc new clocks if (updateClock) { direction.completeOrthonormal(s.clockU, s.clockV); } } clockU.set(s.clockU); clockV.set(s.clockV); // Application.debug("direction=\n"+direction.toString()); } private Coords tmpCoords = new Coords(3); /** * set the normal vector and position for parameters u,v * * @param u * cosinus * @param v * sinus * @param vn * normal vector * @param pos * position */ public void getNormalAndPosition(double u, double v, Coords vn, Coords pos) { vn.setAdd(vn.setMul(clockU, u), tmpCoords.setMul(clockV, v)); pos.setAdd(pos.setMul(vn, thickness), center); if (normal.isDefined()) { vn.setValues(normal, 3); } else if (normalDevD != 0) { vn.setAdd(vn.setMul(vn, normalDevN), tmpCoords.setMul(direction, normalDevD)); } } /** * @return the center of the section */ public Coords getCenter() { return center; } // ////////////////////////////////// // FOR 3D CURVE // ////////////////////////////////// public void set(PlotterBrushSection s, Coords point, float thickness) { setCenter(point); this.thickness = thickness; this.direction.setSub(center, s.getCenter()); direction.calcNorm(); length = direction.getNorm(); direction.mulInside(1 / length); if (!s.clockU.isDefined()) { direction.completeOrthonormal(s.clockU, s.clockV); } clockV.setCrossProduct(direction, s.clockU); clockV.normalize(); // normalize it to avoid little errors propagation clockU.setCrossProduct(clockV, direction); clockU.normalize(); normal.setUndefined(); normalDevD = 0; } }